First Init

Brightcells 8 years ago
commit
80b7f7c9aa
120 changed files with 2970 additions and 0 deletions
  1. 29 0
      .editorconfig
  2. 14 0
      .idea/misc.xml
  3. 8 0
      .idea/modules.xml
  4. 26 0
      .idea/tamron.iml
  5. 634 0
      .idea/workspace.xml
  6. 8 0
      .isort.cfg
  7. 0 0
      account/__init__.py
  8. BIN
      account/__init__.pyc
  9. 23 0
      account/admin.py
  10. BIN
      account/admin.pyc
  11. 55 0
      account/migrations/0001_initial.py
  12. BIN
      account/migrations/0001_initial.pyc
  13. 33 0
      account/migrations/0002_auto_20170619_1635.py
  14. BIN
      account/migrations/0002_auto_20170619_1635.pyc
  15. 19 0
      account/migrations/0003_saleclerkinfo_franchiser_name.py
  16. BIN
      account/migrations/0003_saleclerkinfo_franchiser_name.pyc
  17. 0 0
      account/migrations/__init__.py
  18. BIN
      account/migrations/__init__.pyc
  19. 92 0
      account/models.py
  20. BIN
      account/models.pyc
  21. 4 0
      account/tests.py
  22. 4 0
      account/views.py
  23. 0 0
      api/__init__.py
  24. BIN
      api/__init__.pyc
  25. 4 0
      api/admin.py
  26. BIN
      api/admin.pyc
  27. 0 0
      api/migrations/__init__.py
  28. BIN
      api/migrations/__init__.pyc
  29. 4 0
      api/models.py
  30. BIN
      api/models.pyc
  31. 4 0
      api/tests.py
  32. 11 0
      api/urls.py
  33. BIN
      api/urls.pyc
  34. 4 0
      api/views.py
  35. 9 0
      check.sh
  36. 0 0
      integral/__init__.py
  37. BIN
      integral/__init__.pyc
  38. 15 0
      integral/admin.py
  39. BIN
      integral/admin.pyc
  40. 33 0
      integral/migrations/0001_initial.py
  41. BIN
      integral/migrations/0001_initial.pyc
  42. 19 0
      integral/migrations/0002_auto_20170619_1734.py
  43. BIN
      integral/migrations/0002_auto_20170619_1734.pyc
  44. 0 0
      integral/migrations/__init__.py
  45. BIN
      integral/migrations/__init__.pyc
  46. 36 0
      integral/models.py
  47. BIN
      integral/models.pyc
  48. 4 0
      integral/tests.py
  49. 4 0
      integral/views.py
  50. 3 0
      isort.sh
  51. 11 0
      manage.py
  52. 0 0
      page/__init__.py
  53. BIN
      page/__init__.pyc
  54. 4 0
      page/admin.py
  55. BIN
      page/admin.pyc
  56. 22 0
      page/info_views.py
  57. BIN
      page/info_views.pyc
  58. 0 0
      page/migrations/__init__.py
  59. BIN
      page/migrations/__init__.pyc
  60. 4 0
      page/models.py
  61. BIN
      page/models.pyc
  62. 70 0
      page/oauth_views.py
  63. BIN
      page/oauth_views.pyc
  64. 111 0
      page/sale_views.py
  65. BIN
      page/sale_views.pyc
  66. 74 0
      page/templates/page/clerk_info.html
  67. 198 0
      page/templates/page/clerk_oauth.html
  68. 187 0
      page/templates/page/clerk_sale.html
  69. 4 0
      page/tests.py
  70. 4 0
      page/views.py
  71. BIN
      page/views.pyc
  72. 9 0
      pep8.sh
  73. 0 0
      product/__init__.py
  74. BIN
      product/__init__.pyc
  75. 29 0
      product/admin.py
  76. BIN
      product/admin.pyc
  77. 77 0
      product/migrations/0001_initial.py
  78. BIN
      product/migrations/0001_initial.pyc
  79. 24 0
      product/migrations/0002_auto_20170619_1734.py
  80. BIN
      product/migrations/0002_auto_20170619_1734.pyc
  81. 0 0
      product/migrations/__init__.py
  82. BIN
      product/migrations/__init__.pyc
  83. 99 0
      product/models.py
  84. BIN
      product/models.pyc
  85. 4 0
      product/tests.py
  86. 4 0
      product/views.py
  87. 39 0
      requirements.txt
  88. 0 0
      tamron/__init__.py
  89. BIN
      tamron/__init__.pyc
  90. 13 0
      tamron/basemodels.py
  91. BIN
      tamron/basemodels.pyc
  92. 16 0
      tamron/func_settings.py
  93. BIN
      tamron/func_settings.pyc
  94. 29 0
      tamron/local_settings.py
  95. BIN
      tamron/local_settings.pyc
  96. 254 0
      tamron/settings.py
  97. BIN
      tamron/settings.pyc
  98. 300 0
      tamron/static/tamron/js/jswe.js
  99. 33 0
      tamron/urls.py
  100. BIN
      tamron/urls.pyc
  101. 2 0
      tamron/uwsgi.bak/shutdown.sh
  102. 2 0
      tamron/uwsgi.bak/startup.sh
  103. 27 0
      tamron/uwsgi.bak/tamron.ini
  104. 35 0
      tamron/uwsgi.bak/tamron_nginx.conf
  105. 15 0
      tamron/uwsgi.bak/uwsgi_params
  106. 17 0
      tamron/wsgi.py
  107. BIN
      tamron/wsgi.pyc
  108. 0 0
      utils/__init__.py
  109. BIN
      utils/__init__.pyc
  110. 0 0
      utils/error/__init__.py
  111. BIN
      utils/error/__init__.pyc
  112. 62 0
      utils/error/errno_utils.py
  113. BIN
      utils/error/errno_utils.pyc
  114. 18 0
      utils/error/response_utils.py
  115. BIN
      utils/error/response_utils.pyc
  116. 0 0
      utils/redis/__init__.py
  117. BIN
      utils/redis/__init__.pyc
  118. 6 0
      utils/redis/connect.py
  119. BIN
      utils/redis/connect.pyc
  120. 68 0
      utils/redis/rkeys.py

+ 29 - 0
.editorconfig

@@ -0,0 +1,29 @@
1
+# EditorConfig is awesome: http://EditorConfig.org
2
+
3
+# top-most EditorConfig file
4
+root = true
5
+
6
+# Unix-style newlines with a newline ending every file
7
+[*]
8
+end_of_line = lf
9
+insert_final_newline = false
10
+
11
+# 4 space indentation
12
+[*.py]
13
+indent_style = space
14
+indent_size = 4
15
+
16
+# Tab indentation (no size specified)
17
+[*.js]
18
+indent_style = space
19
+indent_size = 4
20
+
21
+# Tab indentation (no size specified)
22
+[*.html]
23
+indent_style = space
24
+indent_size = 4
25
+
26
+# Matches the exact files either package.json or .travis.yml
27
+[{package.json,.travis.yml}]
28
+indent_style = space
29
+indent_size = 2

+ 14 - 0
.idea/misc.xml

@@ -0,0 +1,14 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<project version="4">
3
+  <component name="ProjectLevelVcsManager" settingsEditedManually="false">
4
+    <OptionsSetting value="true" id="Add" />
5
+    <OptionsSetting value="true" id="Remove" />
6
+    <OptionsSetting value="true" id="Checkout" />
7
+    <OptionsSetting value="true" id="Update" />
8
+    <OptionsSetting value="true" id="Status" />
9
+    <OptionsSetting value="true" id="Edit" />
10
+    <ConfirmationsSetting value="0" id="Add" />
11
+    <ConfirmationsSetting value="0" id="Remove" />
12
+  </component>
13
+  <component name="ProjectRootManager" version="2" project-jdk-name="Python 2.7.12+ (/usr/bin/python2.7)" project-jdk-type="Python SDK" />
14
+</project>

+ 8 - 0
.idea/modules.xml

@@ -0,0 +1,8 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<project version="4">
3
+  <component name="ProjectModuleManager">
4
+    <modules>
5
+      <module fileurl="file://$PROJECT_DIR$/.idea/tamron.iml" filepath="$PROJECT_DIR$/.idea/tamron.iml" />
6
+    </modules>
7
+  </component>
8
+</project>

+ 26 - 0
.idea/tamron.iml

@@ -0,0 +1,26 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<module type="PYTHON_MODULE" version="4">
3
+  <component name="FacetManager">
4
+    <facet type="django" name="Django">
5
+      <configuration>
6
+        <option name="rootFolder" value="$MODULE_DIR$" />
7
+        <option name="settingsModule" value="tamron/settings.py" />
8
+        <option name="manageScript" value="manage.py" />
9
+        <option name="environment" value="&lt;map/&gt;" />
10
+        <option name="commandsToSkip" value="" />
11
+      </configuration>
12
+    </facet>
13
+  </component>
14
+  <component name="NewModuleRootManager">
15
+    <content url="file://$MODULE_DIR$" />
16
+    <orderEntry type="inheritedJdk" />
17
+    <orderEntry type="sourceFolder" forTests="false" />
18
+  </component>
19
+  <component name="TemplatesService">
20
+    <option name="TEMPLATE_CONFIGURATION" value="Django" />
21
+  </component>
22
+  <component name="TestRunnerService">
23
+    <option name="projectConfiguration" value="py.test" />
24
+    <option name="PROJECT_TEST_RUNNER" value="py.test" />
25
+  </component>
26
+</module>

+ 634 - 0
.idea/workspace.xml

@@ -0,0 +1,634 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<project version="4">
3
+  <component name="ChangeListManager">
4
+    <list default="true" id="8287082c-5144-4790-9da1-578e292318f7" name="Default" comment="" />
5
+    <ignored path="tamron.iws" />
6
+    <ignored path=".idea/workspace.xml" />
7
+    <ignored path=".idea/dataSources.local.xml" />
8
+    <option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
9
+    <option name="TRACKING_ENABLED" value="true" />
10
+    <option name="SHOW_DIALOG" value="false" />
11
+    <option name="HIGHLIGHT_CONFLICTS" value="true" />
12
+    <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
13
+    <option name="LAST_RESOLUTION" value="IGNORE" />
14
+  </component>
15
+  <component name="CreatePatchCommitExecutor">
16
+    <option name="PATCH_PATH" value="" />
17
+  </component>
18
+  <component name="ExecutionTargetManager" SELECTED_TARGET="default_target" />
19
+  <component name="FavoritesManager">
20
+    <favorites_list name="tamron" />
21
+  </component>
22
+  <component name="FileEditorManager">
23
+    <leaf>
24
+      <file leaf-file-name="tamron.ini" pinned="false" current-in-tab="false">
25
+        <entry file="file://$PROJECT_DIR$/tamron/uwsgi.bak/tamron.ini">
26
+          <provider selected="true" editor-type-id="text-editor">
27
+            <state relative-caret-position="255">
28
+              <caret line="17" column="61" selection-start-line="17" selection-start-column="61" selection-end-line="17" selection-end-column="61" />
29
+              <folding />
30
+            </state>
31
+          </provider>
32
+        </entry>
33
+      </file>
34
+      <file leaf-file-name="tamron_nginx.conf" pinned="false" current-in-tab="true">
35
+        <entry file="file://$PROJECT_DIR$/tamron/uwsgi.bak/tamron_nginx.conf">
36
+          <provider selected="true" editor-type-id="text-editor">
37
+            <state relative-caret-position="480">
38
+              <caret line="32" column="50" selection-start-line="32" selection-start-column="50" selection-end-line="32" selection-end-column="50" />
39
+              <folding />
40
+            </state>
41
+          </provider>
42
+        </entry>
43
+      </file>
44
+    </leaf>
45
+  </component>
46
+  <component name="FileTemplateManagerImpl">
47
+    <option name="RECENT_TEMPLATES">
48
+      <list>
49
+        <option value="Python Script" />
50
+      </list>
51
+    </option>
52
+  </component>
53
+  <component name="IdeDocumentHistory">
54
+    <option name="CHANGED_PATHS">
55
+      <list>
56
+        <option value="$PROJECT_DIR$/tamron/basemodels.py" />
57
+        <option value="$PROJECT_DIR$/account/admin.py" />
58
+        <option value="$PROJECT_DIR$/product/admin.py" />
59
+        <option value="$PROJECT_DIR$/integral/admin.py" />
60
+        <option value="$PROJECT_DIR$/page/views.py" />
61
+        <option value="$PROJECT_DIR$/product/models.py" />
62
+        <option value="$PROJECT_DIR$/integral/models.py" />
63
+        <option value="$PROJECT_DIR$/tamron/settings.py" />
64
+        <option value="$PROJECT_DIR$/api/urls.py" />
65
+        <option value="$PROJECT_DIR$/tamron/local_settings.py" />
66
+        <option value="$PROJECT_DIR$/page/templates/page/clerk_oauth.html" />
67
+        <option value="$PROJECT_DIR$/page/sale_views.py" />
68
+        <option value="$PROJECT_DIR$/page/templates/page/clerk_sale.html" />
69
+        <option value="$PROJECT_DIR$/page/templates/page/clerk_into.html" />
70
+        <option value="$PROJECT_DIR$/tamron/urls.py" />
71
+        <option value="$PROJECT_DIR$/page/info_views.py" />
72
+        <option value="$PROJECT_DIR$/utils/error/errno_utils.py" />
73
+        <option value="$PROJECT_DIR$/page/oauth_views.py" />
74
+        <option value="$PROJECT_DIR$/account/models.py" />
75
+        <option value="$PROJECT_DIR$/page/templates/page/clerk_info.html" />
76
+        <option value="$PROJECT_DIR$/tamron/uwsgi.bak/tamron.ini" />
77
+        <option value="$PROJECT_DIR$/tamron/uwsgi.bak/tamron_nginx.conf" />
78
+      </list>
79
+    </option>
80
+  </component>
81
+  <component name="JsBuildToolGruntFileManager" detection-done="true" sorting="DEFINITION_ORDER" />
82
+  <component name="JsBuildToolPackageJson" detection-done="true" sorting="DEFINITION_ORDER" />
83
+  <component name="JsGulpfileManager">
84
+    <detection-done>true</detection-done>
85
+    <sorting>DEFINITION_ORDER</sorting>
86
+  </component>
87
+  <component name="ProjectFrameBounds">
88
+    <option name="x" value="65" />
89
+    <option name="y" value="24" />
90
+    <option name="width" value="1301" />
91
+    <option name="height" value="744" />
92
+  </component>
93
+  <component name="ProjectLevelVcsManager" settingsEditedManually="false">
94
+    <OptionsSetting value="true" id="Add" />
95
+    <OptionsSetting value="true" id="Remove" />
96
+    <OptionsSetting value="true" id="Checkout" />
97
+    <OptionsSetting value="true" id="Update" />
98
+    <OptionsSetting value="true" id="Status" />
99
+    <OptionsSetting value="true" id="Edit" />
100
+    <ConfirmationsSetting value="0" id="Add" />
101
+    <ConfirmationsSetting value="0" id="Remove" />
102
+  </component>
103
+  <component name="ProjectView">
104
+    <navigator currentView="ProjectPane" proportions="" version="1">
105
+      <flattenPackages />
106
+      <showMembers />
107
+      <showModules />
108
+      <showLibraryContents />
109
+      <hideEmptyPackages />
110
+      <abbreviatePackageNames />
111
+      <autoscrollToSource />
112
+      <autoscrollFromSource />
113
+      <sortByType />
114
+      <manualOrder />
115
+      <foldersAlwaysOnTop value="true" />
116
+    </navigator>
117
+    <panes>
118
+      <pane id="Scratches" />
119
+      <pane id="Scope" />
120
+      <pane id="ProjectPane">
121
+        <subPane>
122
+          <PATH>
123
+            <PATH_ELEMENT>
124
+              <option name="myItemId" value="tamron" />
125
+              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
126
+            </PATH_ELEMENT>
127
+          </PATH>
128
+          <PATH>
129
+            <PATH_ELEMENT>
130
+              <option name="myItemId" value="tamron" />
131
+              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
132
+            </PATH_ELEMENT>
133
+            <PATH_ELEMENT>
134
+              <option name="myItemId" value="tamron" />
135
+              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
136
+            </PATH_ELEMENT>
137
+          </PATH>
138
+        </subPane>
139
+      </pane>
140
+    </panes>
141
+  </component>
142
+  <component name="PropertiesComponent">
143
+    <property name="last_opened_file_path" value="$PROJECT_DIR$" />
144
+    <property name="WebServerToolWindowFactoryState" value="false" />
145
+    <property name="js-jscs-nodeInterpreter" value="$USER_HOME$/.nvm/versions/node/v6.10.0/bin/node" />
146
+  </component>
147
+  <component name="RecentsManager">
148
+    <key name="CopyFile.RECENT_KEYS">
149
+      <recent name="$PROJECT_DIR$/page" />
150
+      <recent name="$PROJECT_DIR$/page/templates/page" />
151
+    </key>
152
+  </component>
153
+  <component name="RunManager" selected="Django server.tamron">
154
+    <configuration default="true" type="DjangoTestsConfigurationType" factoryName="Django tests">
155
+      <option name="INTERPRETER_OPTIONS" value="" />
156
+      <option name="PARENT_ENVS" value="true" />
157
+      <envs>
158
+        <env name="PYTHONUNBUFFERED" value="1" />
159
+      </envs>
160
+      <option name="SDK_HOME" value="" />
161
+      <option name="WORKING_DIRECTORY" value="" />
162
+      <option name="IS_MODULE_SDK" value="false" />
163
+      <option name="ADD_CONTENT_ROOTS" value="true" />
164
+      <option name="ADD_SOURCE_ROOTS" value="true" />
165
+      <module name="tamron" />
166
+      <EXTENSION ID="PythonCoverageRunConfigurationExtension" enabled="false" sample_coverage="true" runner="coverage.py" />
167
+      <option name="TARGET" value="" />
168
+      <option name="SETTINGS_FILE" value="" />
169
+      <option name="CUSTOM_SETTINGS" value="false" />
170
+      <option name="USE_OPTIONS" value="false" />
171
+      <option name="OPTIONS" value="" />
172
+      <method />
173
+    </configuration>
174
+    <configuration default="true" type="JavascriptDebugType" factoryName="JavaScript Debug">
175
+      <method />
176
+    </configuration>
177
+    <configuration default="true" type="PyBehaveRunConfigurationType" factoryName="Behave">
178
+      <option name="INTERPRETER_OPTIONS" value="" />
179
+      <option name="PARENT_ENVS" value="true" />
180
+      <envs />
181
+      <option name="SDK_HOME" value="" />
182
+      <option name="WORKING_DIRECTORY" value="" />
183
+      <option name="IS_MODULE_SDK" value="false" />
184
+      <option name="ADD_CONTENT_ROOTS" value="true" />
185
+      <option name="ADD_SOURCE_ROOTS" value="true" />
186
+      <module name="tamron" />
187
+      <EXTENSION ID="PythonCoverageRunConfigurationExtension" enabled="false" sample_coverage="true" runner="coverage.py" />
188
+      <option name="ADDITIONAL_ARGS" value="" />
189
+      <method />
190
+    </configuration>
191
+    <configuration default="true" type="PyLettuceRunConfigurationType" factoryName="Lettuce">
192
+      <option name="INTERPRETER_OPTIONS" value="" />
193
+      <option name="PARENT_ENVS" value="true" />
194
+      <envs />
195
+      <option name="SDK_HOME" value="" />
196
+      <option name="WORKING_DIRECTORY" value="" />
197
+      <option name="IS_MODULE_SDK" value="false" />
198
+      <option name="ADD_CONTENT_ROOTS" value="true" />
199
+      <option name="ADD_SOURCE_ROOTS" value="true" />
200
+      <module name="tamron" />
201
+      <EXTENSION ID="PythonCoverageRunConfigurationExtension" enabled="false" sample_coverage="true" runner="coverage.py" />
202
+      <option name="ADDITIONAL_ARGS" value="" />
203
+      <method />
204
+    </configuration>
205
+    <configuration default="true" type="Python.DjangoServer" factoryName="Django server">
206
+      <option name="INTERPRETER_OPTIONS" value="" />
207
+      <option name="PARENT_ENVS" value="true" />
208
+      <envs>
209
+        <env name="PYTHONUNBUFFERED" value="1" />
210
+      </envs>
211
+      <option name="SDK_HOME" value="" />
212
+      <option name="WORKING_DIRECTORY" value="" />
213
+      <option name="IS_MODULE_SDK" value="false" />
214
+      <option name="ADD_CONTENT_ROOTS" value="true" />
215
+      <option name="ADD_SOURCE_ROOTS" value="true" />
216
+      <module name="tamron" />
217
+      <option name="launchJavascriptDebuger" value="false" />
218
+      <option name="port" value="8000" />
219
+      <option name="host" value="" />
220
+      <option name="additionalOptions" value="" />
221
+      <option name="browserUrl" value="" />
222
+      <option name="runTestServer" value="false" />
223
+      <option name="runNoReload" value="false" />
224
+      <option name="useCustomRunCommand" value="false" />
225
+      <option name="customRunCommand" value="" />
226
+      <method />
227
+    </configuration>
228
+    <configuration default="true" type="PythonConfigurationType" factoryName="Python">
229
+      <option name="INTERPRETER_OPTIONS" value="" />
230
+      <option name="PARENT_ENVS" value="true" />
231
+      <envs>
232
+        <env name="PYTHONUNBUFFERED" value="1" />
233
+      </envs>
234
+      <option name="SDK_HOME" value="" />
235
+      <option name="WORKING_DIRECTORY" value="" />
236
+      <option name="IS_MODULE_SDK" value="false" />
237
+      <option name="ADD_CONTENT_ROOTS" value="true" />
238
+      <option name="ADD_SOURCE_ROOTS" value="true" />
239
+      <module name="tamron" />
240
+      <EXTENSION ID="PythonCoverageRunConfigurationExtension" enabled="false" sample_coverage="true" runner="coverage.py" />
241
+      <option name="SCRIPT_NAME" value="" />
242
+      <option name="PARAMETERS" value="" />
243
+      <option name="SHOW_COMMAND_LINE" value="false" />
244
+      <method />
245
+    </configuration>
246
+    <configuration default="true" type="Tox" factoryName="Tox">
247
+      <option name="INTERPRETER_OPTIONS" value="" />
248
+      <option name="PARENT_ENVS" value="true" />
249
+      <envs />
250
+      <option name="SDK_HOME" value="" />
251
+      <option name="WORKING_DIRECTORY" value="" />
252
+      <option name="IS_MODULE_SDK" value="false" />
253
+      <option name="ADD_CONTENT_ROOTS" value="true" />
254
+      <option name="ADD_SOURCE_ROOTS" value="true" />
255
+      <EXTENSION ID="PythonCoverageRunConfigurationExtension" enabled="false" sample_coverage="true" runner="coverage.py" />
256
+      <module name="tamron" />
257
+      <method />
258
+    </configuration>
259
+    <configuration default="true" type="js.build_tools.gulp" factoryName="Gulp.js">
260
+      <node-interpreter>project</node-interpreter>
261
+      <node-options />
262
+      <gulpfile />
263
+      <tasks />
264
+      <arguments />
265
+      <envs />
266
+      <method />
267
+    </configuration>
268
+    <configuration default="true" type="js.build_tools.npm" factoryName="npm">
269
+      <command value="run-script" />
270
+      <scripts />
271
+      <node-interpreter value="project" />
272
+      <envs />
273
+      <method />
274
+    </configuration>
275
+    <configuration default="true" type="tests" factoryName="Attests">
276
+      <option name="INTERPRETER_OPTIONS" value="" />
277
+      <option name="PARENT_ENVS" value="true" />
278
+      <envs />
279
+      <option name="SDK_HOME" value="" />
280
+      <option name="WORKING_DIRECTORY" value="" />
281
+      <option name="IS_MODULE_SDK" value="false" />
282
+      <option name="ADD_CONTENT_ROOTS" value="true" />
283
+      <option name="ADD_SOURCE_ROOTS" value="true" />
284
+      <module name="tamron" />
285
+      <EXTENSION ID="PythonCoverageRunConfigurationExtension" enabled="false" sample_coverage="true" runner="coverage.py" />
286
+      <option name="SCRIPT_NAME" value="" />
287
+      <option name="CLASS_NAME" value="" />
288
+      <option name="METHOD_NAME" value="" />
289
+      <option name="FOLDER_NAME" value="" />
290
+      <option name="TEST_TYPE" value="TEST_SCRIPT" />
291
+      <option name="PATTERN" value="" />
292
+      <option name="USE_PATTERN" value="false" />
293
+      <method />
294
+    </configuration>
295
+    <configuration default="true" type="tests" factoryName="Doctests">
296
+      <option name="INTERPRETER_OPTIONS" value="" />
297
+      <option name="PARENT_ENVS" value="true" />
298
+      <envs />
299
+      <option name="SDK_HOME" value="" />
300
+      <option name="WORKING_DIRECTORY" value="" />
301
+      <option name="IS_MODULE_SDK" value="false" />
302
+      <option name="ADD_CONTENT_ROOTS" value="true" />
303
+      <option name="ADD_SOURCE_ROOTS" value="true" />
304
+      <module name="tamron" />
305
+      <EXTENSION ID="PythonCoverageRunConfigurationExtension" enabled="false" sample_coverage="true" runner="coverage.py" />
306
+      <option name="SCRIPT_NAME" value="" />
307
+      <option name="CLASS_NAME" value="" />
308
+      <option name="METHOD_NAME" value="" />
309
+      <option name="FOLDER_NAME" value="" />
310
+      <option name="TEST_TYPE" value="TEST_SCRIPT" />
311
+      <option name="PATTERN" value="" />
312
+      <option name="USE_PATTERN" value="false" />
313
+      <method />
314
+    </configuration>
315
+    <configuration default="true" type="tests" factoryName="Nosetests">
316
+      <option name="INTERPRETER_OPTIONS" value="" />
317
+      <option name="PARENT_ENVS" value="true" />
318
+      <envs />
319
+      <option name="SDK_HOME" value="" />
320
+      <option name="WORKING_DIRECTORY" value="" />
321
+      <option name="IS_MODULE_SDK" value="false" />
322
+      <option name="ADD_CONTENT_ROOTS" value="true" />
323
+      <option name="ADD_SOURCE_ROOTS" value="true" />
324
+      <module name="tamron" />
325
+      <EXTENSION ID="PythonCoverageRunConfigurationExtension" enabled="false" sample_coverage="true" runner="coverage.py" />
326
+      <option name="SCRIPT_NAME" value="" />
327
+      <option name="CLASS_NAME" value="" />
328
+      <option name="METHOD_NAME" value="" />
329
+      <option name="FOLDER_NAME" value="" />
330
+      <option name="TEST_TYPE" value="TEST_SCRIPT" />
331
+      <option name="PATTERN" value="" />
332
+      <option name="USE_PATTERN" value="false" />
333
+      <option name="PARAMS" value="" />
334
+      <option name="USE_PARAM" value="false" />
335
+      <method />
336
+    </configuration>
337
+    <configuration default="true" type="tests" factoryName="Unittests">
338
+      <option name="INTERPRETER_OPTIONS" value="" />
339
+      <option name="PARENT_ENVS" value="true" />
340
+      <envs />
341
+      <option name="SDK_HOME" value="" />
342
+      <option name="WORKING_DIRECTORY" value="" />
343
+      <option name="IS_MODULE_SDK" value="false" />
344
+      <option name="ADD_CONTENT_ROOTS" value="true" />
345
+      <option name="ADD_SOURCE_ROOTS" value="true" />
346
+      <module name="tamron" />
347
+      <EXTENSION ID="PythonCoverageRunConfigurationExtension" enabled="false" sample_coverage="true" runner="coverage.py" />
348
+      <option name="SCRIPT_NAME" value="" />
349
+      <option name="CLASS_NAME" value="" />
350
+      <option name="METHOD_NAME" value="" />
351
+      <option name="FOLDER_NAME" value="" />
352
+      <option name="TEST_TYPE" value="TEST_SCRIPT" />
353
+      <option name="PATTERN" value="" />
354
+      <option name="USE_PATTERN" value="false" />
355
+      <option name="PUREUNITTEST" value="true" />
356
+      <option name="PARAMS" value="" />
357
+      <option name="USE_PARAM" value="false" />
358
+      <method />
359
+    </configuration>
360
+    <configuration default="true" type="tests" factoryName="py.test">
361
+      <option name="INTERPRETER_OPTIONS" value="" />
362
+      <option name="PARENT_ENVS" value="true" />
363
+      <envs />
364
+      <option name="SDK_HOME" value="" />
365
+      <option name="WORKING_DIRECTORY" value="" />
366
+      <option name="IS_MODULE_SDK" value="false" />
367
+      <option name="ADD_CONTENT_ROOTS" value="true" />
368
+      <option name="ADD_SOURCE_ROOTS" value="true" />
369
+      <module name="tamron" />
370
+      <EXTENSION ID="PythonCoverageRunConfigurationExtension" enabled="false" sample_coverage="true" runner="coverage.py" />
371
+      <option name="SCRIPT_NAME" value="" />
372
+      <option name="CLASS_NAME" value="" />
373
+      <option name="METHOD_NAME" value="" />
374
+      <option name="FOLDER_NAME" value="" />
375
+      <option name="TEST_TYPE" value="TEST_SCRIPT" />
376
+      <option name="PATTERN" value="" />
377
+      <option name="USE_PATTERN" value="false" />
378
+      <option name="testToRun" value="" />
379
+      <option name="keywords" value="" />
380
+      <option name="params" value="" />
381
+      <option name="USE_PARAM" value="false" />
382
+      <option name="USE_KEYWORD" value="false" />
383
+      <method />
384
+    </configuration>
385
+    <configuration default="false" name="tamron" type="Python.DjangoServer" factoryName="Django server">
386
+      <option name="INTERPRETER_OPTIONS" value="" />
387
+      <option name="PARENT_ENVS" value="true" />
388
+      <envs>
389
+        <env name="PYTHONUNBUFFERED" value="1" />
390
+      </envs>
391
+      <option name="SDK_HOME" value="" />
392
+      <option name="WORKING_DIRECTORY" value="" />
393
+      <option name="IS_MODULE_SDK" value="false" />
394
+      <option name="ADD_CONTENT_ROOTS" value="true" />
395
+      <option name="ADD_SOURCE_ROOTS" value="true" />
396
+      <module name="tamron" />
397
+      <option name="launchJavascriptDebuger" value="false" />
398
+      <option name="port" value="8000" />
399
+      <option name="host" value="" />
400
+      <option name="additionalOptions" value="" />
401
+      <option name="browserUrl" value="" />
402
+      <option name="runTestServer" value="false" />
403
+      <option name="runNoReload" value="false" />
404
+      <option name="useCustomRunCommand" value="false" />
405
+      <option name="customRunCommand" value="" />
406
+      <method />
407
+    </configuration>
408
+    <list size="1">
409
+      <item index="0" class="java.lang.String" itemvalue="Django server.tamron" />
410
+    </list>
411
+  </component>
412
+  <component name="ShelveChangesManager" show_recycled="false">
413
+    <option name="remove_strategy" value="false" />
414
+  </component>
415
+  <component name="TaskManager">
416
+    <task active="true" id="Default" summary="Default task">
417
+      <changelist id="8287082c-5144-4790-9da1-578e292318f7" name="Default" comment="" />
418
+      <created>1497849391019</created>
419
+      <option name="number" value="Default" />
420
+      <option name="presentableId" value="Default" />
421
+      <updated>1497849391019</updated>
422
+    </task>
423
+    <servers />
424
+  </component>
425
+  <component name="ToolWindowManager">
426
+    <frame x="65" y="24" width="1301" height="744" extended-state="6" />
427
+    <editor active="false" />
428
+    <layout>
429
+      <window_info id="Project" active="true" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.16756341" sideWeight="0.5" order="0" side_tool="false" content_ui="combo" />
430
+      <window_info id="TODO" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="6" side_tool="false" content_ui="tabs" />
431
+      <window_info id="Event Log" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="true" content_ui="tabs" />
432
+      <window_info id="Database" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
433
+      <window_info id="Version Control" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
434
+      <window_info id="Python Console" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
435
+      <window_info id="Structure" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
436
+      <window_info id="Terminal" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
437
+      <window_info id="Favorites" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="true" content_ui="tabs" />
438
+      <window_info id="Cvs" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="4" side_tool="false" content_ui="tabs" />
439
+      <window_info id="Message" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
440
+      <window_info id="Commander" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
441
+      <window_info id="Inspection" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="5" side_tool="false" content_ui="tabs" />
442
+      <window_info id="Run" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" />
443
+      <window_info id="Hierarchy" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="2" side_tool="false" content_ui="combo" />
444
+      <window_info id="Find" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
445
+      <window_info id="Ant Build" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
446
+      <window_info id="Debug" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
447
+    </layout>
448
+  </component>
449
+  <component name="Vcs.Log.UiProperties">
450
+    <option name="RECENTLY_FILTERED_USER_GROUPS">
451
+      <collection />
452
+    </option>
453
+    <option name="RECENTLY_FILTERED_BRANCH_GROUPS">
454
+      <collection />
455
+    </option>
456
+  </component>
457
+  <component name="VcsContentAnnotationSettings">
458
+    <option name="myLimit" value="2678400000" />
459
+  </component>
460
+  <component name="XDebuggerManager">
461
+    <breakpoint-manager>
462
+      <option name="time" value="2" />
463
+    </breakpoint-manager>
464
+    <watches-manager />
465
+  </component>
466
+  <component name="editorHistoryManager">
467
+    <entry file="file://$PROJECT_DIR$/page/models.py">
468
+      <provider selected="true" editor-type-id="text-editor">
469
+        <state relative-caret-position="0">
470
+          <caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
471
+        </state>
472
+      </provider>
473
+    </entry>
474
+    <entry file="file://$PROJECT_DIR$/account/admin.py">
475
+      <provider selected="true" editor-type-id="text-editor">
476
+        <state relative-caret-position="165">
477
+          <caret line="13" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="23" selection-end-column="0" />
478
+        </state>
479
+      </provider>
480
+    </entry>
481
+    <entry file="file://$PROJECT_DIR$/tamron/basemodels.py">
482
+      <provider selected="true" editor-type-id="text-editor">
483
+        <state relative-caret-position="105">
484
+          <caret line="7" column="94" selection-start-line="7" selection-start-column="79" selection-end-line="7" selection-end-column="94" />
485
+        </state>
486
+      </provider>
487
+    </entry>
488
+    <entry file="file://$PROJECT_DIR$/integral/admin.py">
489
+      <provider selected="true" editor-type-id="text-editor">
490
+        <state relative-caret-position="150">
491
+          <caret line="10" column="38" selection-start-line="10" selection-start-column="38" selection-end-line="10" selection-end-column="38" />
492
+        </state>
493
+      </provider>
494
+    </entry>
495
+    <entry file="file://$PROJECT_DIR$/product/admin.py">
496
+      <provider selected="true" editor-type-id="text-editor">
497
+        <state relative-caret-position="390">
498
+          <caret line="26" column="0" selection-start-line="26" selection-start-column="0" selection-end-line="26" selection-end-column="60" />
499
+        </state>
500
+      </provider>
501
+    </entry>
502
+    <entry file="file://$PROJECT_DIR$/integral/views.py">
503
+      <provider selected="true" editor-type-id="text-editor">
504
+        <state relative-caret-position="60">
505
+          <caret line="4" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="4" selection-end-column="0" />
506
+        </state>
507
+      </provider>
508
+    </entry>
509
+    <entry file="file://$PROJECT_DIR$/page/views.py">
510
+      <provider selected="true" editor-type-id="text-editor">
511
+        <state relative-caret-position="60">
512
+          <caret line="4" column="0" selection-start-line="4" selection-start-column="0" selection-end-line="4" selection-end-column="0" />
513
+        </state>
514
+      </provider>
515
+    </entry>
516
+    <entry file="file://$PROJECT_DIR$/product/models.py">
517
+      <provider selected="true" editor-type-id="text-editor">
518
+        <state relative-caret-position="308">
519
+          <caret line="43" column="104" selection-start-line="43" selection-start-column="104" selection-end-line="43" selection-end-column="104" />
520
+        </state>
521
+      </provider>
522
+    </entry>
523
+    <entry file="file://$PROJECT_DIR$/integral/models.py">
524
+      <provider selected="true" editor-type-id="text-editor">
525
+        <state relative-caret-position="360">
526
+          <caret line="24" column="30" selection-start-line="24" selection-start-column="30" selection-end-line="24" selection-end-column="30" />
527
+        </state>
528
+      </provider>
529
+    </entry>
530
+    <entry file="file://$PROJECT_DIR$/tamron/settings.py">
531
+      <provider selected="true" editor-type-id="text-editor">
532
+        <state relative-caret-position="312">
533
+          <caret line="200" column="6" selection-start-line="200" selection-start-column="0" selection-end-line="200" selection-end-column="6" />
534
+          <folding />
535
+        </state>
536
+      </provider>
537
+    </entry>
538
+    <entry file="file://$PROJECT_DIR$/tamron/local_settings.py">
539
+      <provider selected="true" editor-type-id="text-editor">
540
+        <state relative-caret-position="420">
541
+          <caret line="28" column="32" selection-start-line="28" selection-start-column="32" selection-end-line="28" selection-end-column="32" />
542
+        </state>
543
+      </provider>
544
+    </entry>
545
+    <entry file="file://$PROJECT_DIR$/api/urls.py">
546
+      <provider selected="true" editor-type-id="text-editor">
547
+        <state relative-caret-position="120">
548
+          <caret line="8" column="44" selection-start-line="8" selection-start-column="44" selection-end-line="8" selection-end-column="44" />
549
+        </state>
550
+      </provider>
551
+    </entry>
552
+    <entry file="file://$PROJECT_DIR$/page/templates/page/clerk_oauth.html">
553
+      <provider selected="true" editor-type-id="text-editor">
554
+        <state relative-caret-position="360">
555
+          <caret line="57" column="18" selection-start-line="25" selection-start-column="12" selection-end-line="57" selection-end-column="18" />
556
+          <folding />
557
+        </state>
558
+      </provider>
559
+    </entry>
560
+    <entry file="file://$PROJECT_DIR$/page/templates/page/clerk_sale.html">
561
+      <provider selected="true" editor-type-id="text-editor">
562
+        <state relative-caret-position="273">
563
+          <caret line="160" column="0" selection-start-line="160" selection-start-column="0" selection-end-line="160" selection-end-column="0" />
564
+          <folding />
565
+        </state>
566
+      </provider>
567
+    </entry>
568
+    <entry file="file://$PROJECT_DIR$/utils/error/errno_utils.py">
569
+      <provider selected="true" editor-type-id="text-editor">
570
+        <state relative-caret-position="75">
571
+          <caret line="5" column="26" selection-start-line="5" selection-start-column="6" selection-end-line="5" selection-end-column="26" />
572
+        </state>
573
+      </provider>
574
+    </entry>
575
+    <entry file="file://$PROJECT_DIR$/account/models.py">
576
+      <provider selected="true" editor-type-id="text-editor">
577
+        <state relative-caret-position="521">
578
+          <caret line="88" column="38" selection-start-line="88" selection-start-column="38" selection-end-line="88" selection-end-column="38" />
579
+        </state>
580
+      </provider>
581
+    </entry>
582
+    <entry file="file://$PROJECT_DIR$/tamron/urls.py">
583
+      <provider selected="true" editor-type-id="text-editor">
584
+        <state relative-caret-position="465">
585
+          <caret line="31" column="55" selection-start-line="31" selection-start-column="55" selection-end-line="31" selection-end-column="55" />
586
+        </state>
587
+      </provider>
588
+    </entry>
589
+    <entry file="file://$PROJECT_DIR$/page/sale_views.py">
590
+      <provider selected="true" editor-type-id="text-editor">
591
+        <state relative-caret-position="311">
592
+          <caret line="97" column="18" selection-start-line="97" selection-start-column="10" selection-end-line="97" selection-end-column="18" />
593
+        </state>
594
+      </provider>
595
+    </entry>
596
+    <entry file="file://$PROJECT_DIR$/page/info_views.py">
597
+      <provider selected="true" editor-type-id="text-editor">
598
+        <state relative-caret-position="300">
599
+          <caret line="20" column="42" selection-start-line="20" selection-start-column="42" selection-end-line="20" selection-end-column="42" />
600
+        </state>
601
+      </provider>
602
+    </entry>
603
+    <entry file="file://$PROJECT_DIR$/page/oauth_views.py">
604
+      <provider selected="true" editor-type-id="text-editor">
605
+        <state relative-caret-position="135">
606
+          <caret line="9" column="37" selection-start-line="9" selection-start-column="31" selection-end-line="9" selection-end-column="37" />
607
+        </state>
608
+      </provider>
609
+    </entry>
610
+    <entry file="file://$PROJECT_DIR$/page/templates/page/clerk_info.html">
611
+      <provider selected="true" editor-type-id="text-editor">
612
+        <state relative-caret-position="48">
613
+          <caret line="44" column="0" selection-start-line="44" selection-start-column="0" selection-end-line="44" selection-end-column="0" />
614
+        </state>
615
+      </provider>
616
+    </entry>
617
+    <entry file="file://$PROJECT_DIR$/tamron/uwsgi.bak/tamron.ini">
618
+      <provider selected="true" editor-type-id="text-editor">
619
+        <state relative-caret-position="255">
620
+          <caret line="17" column="61" selection-start-line="17" selection-start-column="61" selection-end-line="17" selection-end-column="61" />
621
+          <folding />
622
+        </state>
623
+      </provider>
624
+    </entry>
625
+    <entry file="file://$PROJECT_DIR$/tamron/uwsgi.bak/tamron_nginx.conf">
626
+      <provider selected="true" editor-type-id="text-editor">
627
+        <state relative-caret-position="480">
628
+          <caret line="32" column="50" selection-start-line="32" selection-start-column="50" selection-end-line="32" selection-end-column="50" />
629
+          <folding />
630
+        </state>
631
+      </provider>
632
+    </entry>
633
+  </component>
634
+</project>

+ 8 - 0
.isort.cfg

@@ -0,0 +1,8 @@
1
+# See the menu of settings available here:
2
+#   https://github.com/timothycrosley/isort/wiki/isort-Settings
3
+
4
+[settings]
5
+indent='    '
6
+line_length=120
7
+lines_after_imports=2
8
+skip=migrations

+ 0 - 0
account/__init__.py


BIN
account/__init__.pyc


+ 23 - 0
account/admin.py

@@ -0,0 +1,23 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+from django.contrib import admin
4
+
5
+from account.models import FranchiserInfo, SaleclerkInfo
6
+
7
+
8
+class FranchiserInfoAdmin(admin.ModelAdmin):
9
+    readonly_fields = ('franchiser_id', )
10
+    list_display = ('franchiser_id', 'franchiser_name', 'franchiser_addr', 'franchiser_phone', 'franchiser_boss_name', 'franchiser_boss_phone', 'status', 'created_at', 'updated_at')
11
+    search_fields = ('franchiser_id', 'franchiser_name', 'franchiser_addr', 'franchiser_phone', 'franchiser_boss_name', 'franchiser_boss_phone')
12
+    list_filter = ('status', )
13
+
14
+
15
+class SaleclerkInfoAdmin(admin.ModelAdmin):
16
+    readonly_fields = ('franchiser_id', )
17
+    list_display = ('franchiser_id', 'clerk_id', 'clerk_name', 'clerk_sex', 'clerk_phone', 'user_status', 'status', 'created_at', 'updated_at')
18
+    search_fields = ('franchiser_id', 'clerk_id', 'clerk_name', 'clerk_phone')
19
+    list_filter = ('user_status', 'status')
20
+
21
+
22
+admin.site.register(FranchiserInfo, FranchiserInfoAdmin)
23
+admin.site.register(SaleclerkInfo, SaleclerkInfoAdmin)

BIN
account/admin.pyc


+ 55 - 0
account/migrations/0001_initial.py

@@ -0,0 +1,55 @@
1
+# -*- coding: utf-8 -*-
2
+from __future__ import unicode_literals
3
+
4
+from django.db import models, migrations
5
+import shortuuidfield.fields
6
+
7
+
8
+class Migration(migrations.Migration):
9
+
10
+    dependencies = [
11
+    ]
12
+
13
+    operations = [
14
+        migrations.CreateModel(
15
+            name='FranchiserInfo',
16
+            fields=[
17
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
18
+                ('status', models.BooleanField(default=True, help_text='\u72b6\u6001', db_index=True, verbose_name='status')),
19
+                ('created_at', models.DateTimeField(help_text='\u521b\u5efa\u65f6\u95f4', verbose_name='created_at', auto_now_add=True)),
20
+                ('updated_at', models.DateTimeField(help_text='\u66f4\u65b0\u65f6\u95f4', verbose_name='updated_at', auto_now=True)),
21
+                ('franchiser_id', shortuuidfield.fields.ShortUUIDField(editable=False, max_length=22, blank=True, help_text='\u7ecf\u9500\u5546\u552f\u4e00\u6807\u8bc6', unique=True, db_index=True)),
22
+                ('franchiser_name', models.CharField(help_text='\u7ecf\u9500\u5546\u540d\u79f0', max_length=255, null=True, verbose_name='franchiser_name', blank=True)),
23
+                ('franchiser_addr', models.CharField(help_text='\u7ecf\u9500\u5546\u5730\u5740', max_length=255, null=True, verbose_name='franchiser_addr', blank=True)),
24
+                ('franchiser_phone', models.CharField(help_text='\u7ecf\u9500\u5546\u8054\u7cfb\u7535\u8bdd', max_length=255, null=True, verbose_name='franchiser_phone', blank=True)),
25
+                ('franchiser_boss_name', models.CharField(help_text='\u7ecf\u9500\u5546\u8001\u677f\u540d\u79f0', max_length=255, null=True, verbose_name='franchiser_boss_name', blank=True)),
26
+                ('franchiser_boss_phone', models.CharField(help_text='\u7ecf\u9500\u5546\u8001\u677f\u8054\u7cfb\u7535\u8bdd', max_length=255, null=True, verbose_name='franchiser_boss_phone', blank=True)),
27
+            ],
28
+            options={
29
+                'verbose_name': 'franchiserinfo',
30
+                'verbose_name_plural': 'franchiserinfo',
31
+            },
32
+        ),
33
+        migrations.CreateModel(
34
+            name='SaleclerkInfo',
35
+            fields=[
36
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
37
+                ('status', models.BooleanField(default=True, help_text='\u72b6\u6001', db_index=True, verbose_name='status')),
38
+                ('created_at', models.DateTimeField(help_text='\u521b\u5efa\u65f6\u95f4', verbose_name='created_at', auto_now_add=True)),
39
+                ('updated_at', models.DateTimeField(help_text='\u66f4\u65b0\u65f6\u95f4', verbose_name='updated_at', auto_now=True)),
40
+                ('franchiser_id', models.CharField(max_length=255, blank=True, help_text='\u7ecf\u9500\u5546\u552f\u4e00\u6807\u8bc6', null=True, verbose_name='franchiser_id', db_index=True)),
41
+                ('clerk_id', shortuuidfield.fields.ShortUUIDField(editable=False, max_length=22, blank=True, help_text='\u5e97\u5458\u552f\u4e00\u6807\u8bc6', unique=True, db_index=True)),
42
+                ('clerk_name', models.CharField(help_text='\u5e97\u5458\u540d\u79f0', max_length=255, null=True, verbose_name='clerk_name', blank=True)),
43
+                ('clerk_sex', models.IntegerField(default=1, help_text='\u5e97\u5458\u6027\u522b', verbose_name='clerk_sex', choices=[(1, '\u7537'), (0, '\u5973')])),
44
+                ('clerk_phone', models.CharField(help_text='\u5e97\u5458\u8054\u7cfb\u7535\u8bdd', max_length=255, null=True, verbose_name='clerk_phone', blank=True)),
45
+                ('openid', models.CharField(null=True, max_length=255, blank=True, help_text='\u5fae\u4fe1 OpenID', unique=True, verbose_name='openid', db_index=True)),
46
+                ('unionid', models.CharField(null=True, max_length=255, blank=True, help_text='\u5fae\u4fe1 UnionID', unique=True, verbose_name='unionid', db_index=True)),
47
+                ('user_status', models.IntegerField(default=0, verbose_name='user_status', choices=[(-1, '\u5df2\u62d2\u7edd'), (0, '\u672a\u9a8c\u8bc1'), (1, '\u5df2\u6fc0\u6d3b'), (2, '\u5df2\u7981\u7528'), (3, '\u5df2\u5220\u9664'), (10, '\u5df2\u5206\u914d')])),
48
+                ('refused_reason', models.TextField(help_text='\u5ba1\u6838\u62d2\u7edd\u539f\u56e0', null=True, verbose_name='refused_reason', blank=True)),
49
+            ],
50
+            options={
51
+                'verbose_name': 'saleclerkinfo',
52
+                'verbose_name_plural': 'saleclerkinfo',
53
+            },
54
+        ),
55
+    ]

BIN
account/migrations/0001_initial.pyc


+ 33 - 0
account/migrations/0002_auto_20170619_1635.py

@@ -0,0 +1,33 @@
1
+# -*- coding: utf-8 -*-
2
+from __future__ import unicode_literals
3
+
4
+from django.db import models, migrations
5
+
6
+
7
+class Migration(migrations.Migration):
8
+
9
+    dependencies = [
10
+        ('account', '0001_initial'),
11
+    ]
12
+
13
+    operations = [
14
+        migrations.AlterModelOptions(
15
+            name='franchiserinfo',
16
+            options={'verbose_name': '\u7ecf\u9500\u5546\u4fe1\u606f\u8868', 'verbose_name_plural': '\u7ecf\u9500\u5546\u4fe1\u606f\u8868'},
17
+        ),
18
+        migrations.AddField(
19
+            model_name='saleclerkinfo',
20
+            name='integral',
21
+            field=models.IntegerField(default=0, help_text='\u79ef\u5206', verbose_name='integral'),
22
+        ),
23
+        migrations.AlterField(
24
+            model_name='saleclerkinfo',
25
+            name='clerk_sex',
26
+            field=models.IntegerField(default=1, help_text='\u5e97\u5458\u6027\u522b', db_index=True, verbose_name='clerk_sex', choices=[(1, '\u7537'), (0, '\u5973')]),
27
+        ),
28
+        migrations.AlterField(
29
+            model_name='saleclerkinfo',
30
+            name='user_status',
31
+            field=models.IntegerField(default=0, help_text='\u7528\u6237\u72b6\u6001', db_index=True, verbose_name='user_status', choices=[(-1, '\u5df2\u62d2\u7edd'), (0, '\u672a\u9a8c\u8bc1'), (1, '\u5df2\u6fc0\u6d3b'), (2, '\u5df2\u7981\u7528'), (3, '\u5df2\u5220\u9664'), (10, '\u5df2\u5206\u914d')]),
32
+        ),
33
+    ]

BIN
account/migrations/0002_auto_20170619_1635.pyc


+ 19 - 0
account/migrations/0003_saleclerkinfo_franchiser_name.py

@@ -0,0 +1,19 @@
1
+# -*- coding: utf-8 -*-
2
+from __future__ import unicode_literals
3
+
4
+from django.db import models, migrations
5
+
6
+
7
+class Migration(migrations.Migration):
8
+
9
+    dependencies = [
10
+        ('account', '0002_auto_20170619_1635'),
11
+    ]
12
+
13
+    operations = [
14
+        migrations.AddField(
15
+            model_name='saleclerkinfo',
16
+            name='franchiser_name',
17
+            field=models.CharField(help_text='\u7ecf\u9500\u5546\u540d\u79f0', max_length=255, null=True, verbose_name='franchiser_name', blank=True),
18
+        ),
19
+    ]

BIN
account/migrations/0003_saleclerkinfo_franchiser_name.pyc


+ 0 - 0
account/migrations/__init__.py


BIN
account/migrations/__init__.pyc


+ 92 - 0
account/models.py

@@ -0,0 +1,92 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+from django.db import models
4
+from django.utils.translation import ugettext_lazy as _
5
+from shortuuidfield import ShortUUIDField
6
+
7
+from tamron.basemodels import CreateUpdateMixin
8
+
9
+
10
+class FranchiserInfo(CreateUpdateMixin):
11
+    franchiser_id = ShortUUIDField(_(u'franchiser_id'), max_length=255, help_text=u'经销商唯一标识', db_index=True, unique=True)
12
+    franchiser_name = models.CharField(_(u'franchiser_name'), max_length=255, blank=True, null=True, help_text=u'经销商名称')
13
+    franchiser_addr = models.CharField(_(u'franchiser_addr'), max_length=255, blank=True, null=True, help_text=u'经销商地址')
14
+    franchiser_phone = models.CharField(_(u'franchiser_phone'), max_length=255, blank=True, null=True, help_text=u'经销商联系电话')
15
+    franchiser_boss_name = models.CharField(_(u'franchiser_boss_name'), max_length=255, blank=True, null=True, help_text=u'经销商老板名称')
16
+    franchiser_boss_phone = models.CharField(_(u'franchiser_boss_phone'), max_length=255, blank=True, null=True, help_text=u'经销商老板联系电话')
17
+
18
+    class Meta:
19
+        verbose_name = _(u'经销商信息表')
20
+        verbose_name_plural = _(u'经销商信息表')
21
+
22
+    def __unicode__(self):
23
+        return unicode(self.pk)
24
+
25
+    @property
26
+    def data(self):
27
+        return {
28
+            'franchiser_id': self.franchiser_id,
29
+            'franchiser_name': self.franchiser_name,
30
+        }
31
+
32
+
33
+class SaleclerkInfo(CreateUpdateMixin):
34
+    MALE = 1
35
+    FEMALE = 0
36
+
37
+    SEX_TYPE = (
38
+        (MALE, u'男'),
39
+        (FEMALE, u'女'),
40
+    )
41
+
42
+    REFUSED = -1
43
+    UNVERIFIED = 0
44
+    ACTIVATED = 1
45
+    DISABLED = 2
46
+    DELETED = 3
47
+    ASSIGN = 10
48
+
49
+    USER_STATUS = (
50
+        (REFUSED, u'已拒绝'),
51
+        (UNVERIFIED, u'未验证'),
52
+        (ACTIVATED, u'已激活'),
53
+        (DISABLED, u'已禁用'),
54
+        (DELETED, u'已删除'),
55
+        (ASSIGN, u'已分配'),
56
+    )
57
+
58
+    franchiser_id = models.CharField(_(u'franchiser_id'), max_length=255, blank=True, null=True, help_text=u'经销商唯一标识', db_index=True)
59
+    franchiser_name = models.CharField(_(u'franchiser_name'), max_length=255, blank=True, null=True, help_text=u'经销商名称')
60
+    clerk_id = ShortUUIDField(_(u'clerk_id'), max_length=255, help_text=u'店员唯一标识', db_index=True, unique=True)
61
+    clerk_name = models.CharField(_(u'clerk_name'), max_length=255, blank=True, null=True, help_text=u'店员名称')
62
+    clerk_sex = models.IntegerField(_(u'clerk_sex'), choices=SEX_TYPE, default=MALE, help_text=u'店员性别', db_index=True)
63
+    clerk_phone = models.CharField(_(u'clerk_phone'), max_length=255, blank=True, null=True, help_text=u'店员联系电话')
64
+
65
+    openid = models.CharField(_(u'openid'), max_length=255, blank=True, null=True, help_text=u'微信 OpenID', db_index=True, unique=True)
66
+    unionid = models.CharField(_(u'unionid'), max_length=255, blank=True, null=True, help_text=u'微信 UnionID', db_index=True, unique=True)
67
+
68
+    integral = models.IntegerField(_(u'integral'), default=0, help_text=u'积分')
69
+
70
+    user_status = models.IntegerField(_(u'user_status'), choices=USER_STATUS, default=UNVERIFIED, help_text=u'用户状态', db_index=True)
71
+    refused_reason = models.TextField(_(u'refused_reason'), blank=True, null=True, help_text=u'审核拒绝原因')
72
+
73
+    class Meta:
74
+        verbose_name = _(u'saleclerkinfo')
75
+        verbose_name_plural = _(u'saleclerkinfo')
76
+
77
+    def __unicode__(self):
78
+        return unicode(self.pk)
79
+
80
+    @property
81
+    def data(self):
82
+        return {
83
+            'franchiser_id': self.franchiser_id,
84
+            'franchiser_name': self.franchiser_name,
85
+            'clerk_id': self.clerk_id,
86
+            'clerk_name': self.clerk_name,
87
+            'clerk_sex': self.clerk_sex,
88
+            'clerk_phone': self.clerk_phone,
89
+            'integral': self.integral,
90
+            'status': self.user_status,
91
+            'refused_reason': self.refused_reason,
92
+        }

BIN
account/models.pyc


+ 4 - 0
account/tests.py

@@ -0,0 +1,4 @@
1
+from django.test import TestCase
2
+
3
+
4
+# Create your tests here.

+ 4 - 0
account/views.py

@@ -0,0 +1,4 @@
1
+from django.shortcuts import render
2
+
3
+
4
+# Create your views here.

+ 0 - 0
api/__init__.py


BIN
api/__init__.pyc


+ 4 - 0
api/admin.py

@@ -0,0 +1,4 @@
1
+from django.contrib import admin
2
+
3
+
4
+# Register your models here.

BIN
api/admin.pyc


+ 0 - 0
api/migrations/__init__.py


BIN
api/migrations/__init__.pyc


+ 4 - 0
api/models.py

@@ -0,0 +1,4 @@
1
+from django.db import models
2
+
3
+
4
+# Create your models here.

BIN
api/models.pyc


+ 4 - 0
api/tests.py

@@ -0,0 +1,4 @@
1
+from django.test import TestCase
2
+
3
+
4
+# Create your tests here.

+ 11 - 0
api/urls.py

@@ -0,0 +1,11 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+from django.conf.urls import url
4
+
5
+from page import oauth_views, sale_views
6
+
7
+
8
+urlpatterns = [
9
+    url(r'^clerk/submit$', oauth_views.clerk_submit_api, name='clerk_submit_api'),  # 店员信息提交
10
+    url(r'^clerk/sale/submit$', sale_views.clerk_sale_submit_api, name='clerk_sale_submit_api'),  # 店员销售信息提交
11
+]

BIN
api/urls.pyc


+ 4 - 0
api/views.py

@@ -0,0 +1,4 @@
1
+from django.shortcuts import render
2
+
3
+
4
+# Create your views here.

+ 9 - 0
check.sh

@@ -0,0 +1,9 @@
1
+#!/bin/bash
2
+
3
+echo '>> iSort'
4
+./isort.sh
5
+echo
6
+
7
+echo '>> PEP8'
8
+./pep8.sh
9
+echo

+ 0 - 0
integral/__init__.py


BIN
integral/__init__.pyc


+ 15 - 0
integral/admin.py

@@ -0,0 +1,15 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+from django.contrib import admin
4
+
5
+from integral.models import SaleclerkIntegralIncomeExpensesInfo
6
+
7
+
8
+class SaleclerkIntegralIncomeExpensesInfoAdmin(admin.ModelAdmin):
9
+    readonly_fields = ('franchiser_id', 'clerk_id', 'type', 'code', 'integral', 'left_integral')
10
+    list_display = ('franchiser_id', 'clerk_id', 'type', 'code', 'integral', 'left_integral', 'remark', 'status', 'created_at', 'updated_at')
11
+    search_fields = ('code', 'remark')
12
+    list_filter = ('franchiser_id', 'type', 'status')
13
+
14
+
15
+admin.site.register(SaleclerkIntegralIncomeExpensesInfo, SaleclerkIntegralIncomeExpensesInfoAdmin)

BIN
integral/admin.pyc


+ 33 - 0
integral/migrations/0001_initial.py

@@ -0,0 +1,33 @@
1
+# -*- coding: utf-8 -*-
2
+from __future__ import unicode_literals
3
+
4
+from django.db import models, migrations
5
+
6
+
7
+class Migration(migrations.Migration):
8
+
9
+    dependencies = [
10
+    ]
11
+
12
+    operations = [
13
+        migrations.CreateModel(
14
+            name='SaleclerkIntegralIncomeExpensesInfo',
15
+            fields=[
16
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
17
+                ('status', models.BooleanField(default=True, help_text='\u72b6\u6001', db_index=True, verbose_name='status')),
18
+                ('created_at', models.DateTimeField(help_text='\u521b\u5efa\u65f6\u95f4', verbose_name='created_at', auto_now_add=True)),
19
+                ('updated_at', models.DateTimeField(help_text='\u66f4\u65b0\u65f6\u95f4', verbose_name='updated_at', auto_now=True)),
20
+                ('franchiser_id', models.CharField(max_length=255, blank=True, help_text='\u7ecf\u9500\u5546\u552f\u4e00\u6807\u8bc6', null=True, verbose_name='franchiser_id', db_index=True)),
21
+                ('clerk_id', models.CharField(max_length=255, blank=True, help_text='\u5e97\u5458\u552f\u4e00\u6807\u8bc6', null=True, verbose_name='clerk_id', db_index=True)),
22
+                ('type', models.IntegerField(default=0, help_text='\u6536\u652f\u7c7b\u522b', db_index=True, verbose_name='type', choices=[(0, '\u6536\u5165'), (1, '\u652f\u51fa'), (2, '\u89e3\u51bb')])),
23
+                ('code', models.CharField(help_text='\u673a\u8eab\u7801', max_length=255, null=True, verbose_name='code', blank=True)),
24
+                ('integral', models.IntegerField(default=0, help_text='\u589e\u51cf\u79ef\u5206', verbose_name='integral')),
25
+                ('left_integral', models.IntegerField(default=0, help_text='\u79ef\u5206\u589e\u51cf\u540e\u6570\u91cf(\u5206)', verbose_name='left_integral')),
26
+                ('remark', models.CharField(help_text='\u5907\u6ce8', max_length=255, null=True, verbose_name='remark', blank=True)),
27
+            ],
28
+            options={
29
+                'verbose_name': 'saleclerkintegralincomeexpensesinfo',
30
+                'verbose_name_plural': 'saleclerkintegralincomeexpensesinfo',
31
+            },
32
+        ),
33
+    ]

BIN
integral/migrations/0001_initial.pyc


+ 19 - 0
integral/migrations/0002_auto_20170619_1734.py

@@ -0,0 +1,19 @@
1
+# -*- coding: utf-8 -*-
2
+from __future__ import unicode_literals
3
+
4
+from django.db import models, migrations
5
+
6
+
7
+class Migration(migrations.Migration):
8
+
9
+    dependencies = [
10
+        ('integral', '0001_initial'),
11
+    ]
12
+
13
+    operations = [
14
+        migrations.AlterField(
15
+            model_name='saleclerkintegralincomeexpensesinfo',
16
+            name='code',
17
+            field=models.CharField(max_length=255, blank=True, help_text='\u673a\u8eab\u7801', null=True, verbose_name='code', db_index=True),
18
+        ),
19
+    ]

BIN
integral/migrations/0002_auto_20170619_1734.pyc


+ 0 - 0
integral/migrations/__init__.py


BIN
integral/migrations/__init__.pyc


+ 36 - 0
integral/models.py

@@ -0,0 +1,36 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+from django.db import models
4
+from django.utils.translation import ugettext_lazy as _
5
+
6
+from tamron.basemodels import CreateUpdateMixin
7
+
8
+
9
+class SaleclerkIntegralIncomeExpensesInfo(CreateUpdateMixin):
10
+    INCOME = 0
11
+    EXPENSE = 1
12
+    UNFREEZE = 2
13
+
14
+    TYPE = (
15
+        (INCOME, u'收入'),
16
+        (EXPENSE, u'支出'),
17
+        (UNFREEZE, u'解冻'),
18
+    )
19
+
20
+    franchiser_id = models.CharField(_(u'franchiser_id'), max_length=255, blank=True, null=True, help_text=u'经销商唯一标识', db_index=True)
21
+    clerk_id = models.CharField(_(u'clerk_id'), max_length=255, blank=True, null=True, help_text=u'店员唯一标识', db_index=True)
22
+
23
+    type = models.IntegerField(_(u'type'), choices=TYPE, default=INCOME, help_text=u'收支类别', db_index=True)
24
+
25
+    code = models.CharField(_(u'code'), max_length=255, blank=True, null=True, help_text=u'机身码', db_index=True)
26
+    integral = models.IntegerField(_(u'integral'), default=0, help_text=u'增减积分')
27
+    left_integral = models.IntegerField(_(u'left_integral'), default=0, help_text=u'积分增减后数量(分)')
28
+
29
+    remark = models.CharField(_(u'remark'), max_length=255, blank=True, null=True, help_text=u'备注')
30
+
31
+    class Meta:
32
+        verbose_name = _(u'saleclerkintegralincomeexpensesinfo')
33
+        verbose_name_plural = _(u'saleclerkintegralincomeexpensesinfo')
34
+
35
+    def __unicode__(self):
36
+        return unicode(self.pk)

BIN
integral/models.pyc


+ 4 - 0
integral/tests.py

@@ -0,0 +1,4 @@
1
+from django.test import TestCase
2
+
3
+
4
+# Create your tests here.

+ 4 - 0
integral/views.py

@@ -0,0 +1,4 @@
1
+from django.shortcuts import render
2
+
3
+
4
+# Create your views here.

+ 3 - 0
isort.sh

@@ -0,0 +1,3 @@
1
+#!/bin/bash
2
+
3
+isort -rc -sp . .

+ 11 - 0
manage.py

@@ -0,0 +1,11 @@
1
+#!/usr/bin/env python
2
+import os
3
+import sys
4
+
5
+
6
+if __name__ == "__main__":
7
+    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "tamron.settings")
8
+
9
+    from django.core.management import execute_from_command_line
10
+
11
+    execute_from_command_line(sys.argv)

+ 0 - 0
page/__init__.py


BIN
page/__init__.pyc


+ 4 - 0
page/admin.py

@@ -0,0 +1,4 @@
1
+from django.contrib import admin
2
+
3
+
4
+# Register your models here.

BIN
page/admin.pyc


+ 22 - 0
page/info_views.py

@@ -0,0 +1,22 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+from __future__ import division
4
+
5
+from django.conf import settings
6
+from django.shortcuts import render
7
+
8
+from account.models import SaleclerkInfo
9
+
10
+
11
+def clerk_info_oauth(request):
12
+    unionid = request.GET.get('unionid', '')
13
+
14
+    try:
15
+        clerk = SaleclerkInfo.objects.get(unionid=unionid)
16
+    except SaleclerkInfo.DoesNotExist:
17
+        clerk = None
18
+
19
+    return render(request, 'page/clerk_info.html', {
20
+        'domain': settings.DOMAIN,
21
+        'clerk_info': clerk and clerk.data,
22
+    })

BIN
page/info_views.pyc


+ 0 - 0
page/migrations/__init__.py


BIN
page/migrations/__init__.pyc


+ 4 - 0
page/models.py

@@ -0,0 +1,4 @@
1
+from django.db import models
2
+
3
+
4
+# Create your models here.

BIN
page/models.pyc


+ 70 - 0
page/oauth_views.py

@@ -0,0 +1,70 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+from __future__ import division
4
+
5
+from django.conf import settings
6
+from django.db import transaction
7
+from django.shortcuts import render
8
+from logit import logit
9
+
10
+from account.models import FranchiserInfo, SaleclerkInfo
11
+from utils.error.errno_utils import FranchiserStatusCode, SaleclerkStatusCode
12
+from utils.error.response_utils import response
13
+
14
+
15
+def clerk_oauth(request):
16
+    unionid = request.GET.get('unionid', '')
17
+
18
+    chisers = FranchiserInfo.objects.filter(status=True)
19
+    chisers = [chiser.data for chiser in chisers]
20
+
21
+    try:
22
+        clerk = SaleclerkInfo.objects.get(unionid=unionid)
23
+    except SaleclerkInfo.DoesNotExist:
24
+        clerk = None
25
+
26
+    return render(request, 'page/clerk_oauth.html', {
27
+        'domain': settings.DOMAIN,
28
+        'chisers': chisers,
29
+        'clerk_info': clerk and clerk.data,
30
+        'modified': bool((not clerk) or (clerk and clerk.user_status in [SaleclerkInfo.UNVERIFIED, SaleclerkInfo.REFUSED])),  # 是否可以更改信息
31
+    })
32
+
33
+
34
+@logit
35
+@transaction.atomic
36
+def clerk_submit_api(request):
37
+    """ 店员授权信息提交 """
38
+    unionid = request.POST.get('unionid', '')
39
+    openid = request.POST.get('openid', '')
40
+    phone = request.POST.get('phone', '')
41
+    chiser = request.POST.get('chiser', '')
42
+
43
+    if SaleclerkInfo.objects.filter(clerk_phone=phone).exclude(unionid=unionid).exists():
44
+        return response(SaleclerkStatusCode.CLERK_PHONE_ALREADY_EXISTS)
45
+
46
+    try:
47
+        franchiser = FranchiserInfo.objects.get(franchiser_id=chiser)
48
+    except FranchiserInfo.DoesNotExist:
49
+        return response(FranchiserStatusCode.CHISER_NOT_FOUND)
50
+
51
+    fields = {
52
+        'franchiser_id': chiser,
53
+        'franchiser_name': franchiser.franchiser_name,
54
+        'clerk_name': request.POST.get('name', ''),
55
+        'clerk_sex': int(request.POST.get('sex', 1)),
56
+        'clerk_phone': phone,
57
+        'openid': openid,
58
+        'user_status': SaleclerkInfo.UNVERIFIED,
59
+    }
60
+
61
+    lensman, created = SaleclerkInfo.objects.select_for_update().get_or_create(unionid=unionid, defaults=fields)
62
+    # 状态为 UNVERIFIED 的允许修改, 其他需要登录摄影师 APP 进行信息的修改
63
+    if lensman.user_status not in [SaleclerkInfo.UNVERIFIED, SaleclerkInfo.REFUSED]:
64
+        return response(SaleclerkInfo.LENSMAN_ALREADY_NOT_UNVERIFIED)
65
+    if not created:
66
+        for key, value in fields.iteritems():
67
+            setattr(lensman, key, value)
68
+        lensman.save()
69
+
70
+    return response(200, 'Submit Success', u'提交成功', {})

BIN
page/oauth_views.pyc


+ 111 - 0
page/sale_views.py

@@ -0,0 +1,111 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+from __future__ import division
4
+
5
+from django.conf import settings
6
+from django.db import transaction
7
+from django.shortcuts import render
8
+from logit import logit
9
+
10
+from account.models import SaleclerkInfo
11
+from integral.models import SaleclerkIntegralIncomeExpensesInfo
12
+from product.models import ProductCodeSubmitLogInfo, ProductInfo, ProductModelInfo
13
+from utils.error.errno_utils import ProductModelStatusCode, ProductStatusCode, SaleclerkStatusCode
14
+from utils.error.response_utils import response
15
+
16
+
17
+def clerk_sale_oauth(request):
18
+    unionid = request.GET.get('unionid', '')
19
+
20
+    models = ProductModelInfo.objects.filter(status=True)
21
+    models = [model.data for model in models]
22
+
23
+    try:
24
+        clerk = SaleclerkInfo.objects.get(unionid=unionid)
25
+    except SaleclerkInfo.DoesNotExist:
26
+        clerk = None
27
+
28
+    return render(request, 'page/clerk_sale.html', {
29
+        'domain': settings.DOMAIN,
30
+        'models': models,
31
+        'clerk_info': clerk and clerk.data,
32
+    })
33
+
34
+
35
+@logit
36
+@transaction.atomic
37
+def clerk_sale_submit_api(request):
38
+    """ 店员信息提交 """
39
+    clerk_id = request.POST.get('clerk_id', '')
40
+    model_id = request.POST.get('model_id', '')
41
+    code = request.POST.get('code', '')
42
+    name = request.POST.get('name', '')
43
+    sex = int(request.POST.get('sex', 1))
44
+    age = int(request.POST.get('age', 1))
45
+    phone = request.POST.get('phone', '')
46
+
47
+    # 店员是否存在
48
+    try:
49
+        clerk = SaleclerkInfo.objects.select_for_update().get(clerk_id=clerk_id)
50
+    except SaleclerkInfo.DoesNotExist:
51
+        return response(SaleclerkStatusCode.CLERK_NOT_FOUND)
52
+
53
+    # 店员是否激活
54
+    if clerk.user_status != SaleclerkInfo.ACTIVATED:
55
+        return response(SaleclerkStatusCode.CLERK_NOT_ACTIVATED)
56
+
57
+    # 型号是否存在
58
+    try:
59
+        model = ProductModelInfo.objects.get(model_id=model_id)
60
+    except ProductModelInfo.DoesNotExist:
61
+        return response(ProductModelStatusCode.MODEL_NOT_FOUND)
62
+
63
+    # 记录销售提交记录
64
+    ProductCodeSubmitLogInfo.objects.create(
65
+        model_id=model.model_id,
66
+        model_name=model.model_name,
67
+        code=code,
68
+        franchiser_id=clerk.franchiser_id,
69
+        clerk_id=clerk.clerk_id,
70
+        consumer_name=name,
71
+        consumer_sex=sex,
72
+        consumer_age=age,
73
+        consumer_phone=phone,
74
+    )
75
+
76
+    # 产品是否存在
77
+    try:
78
+        product = ProductInfo.objects.select_for_update().get(model_id=model_id, code=code)
79
+    except ProductInfo.DoesNotExist:
80
+        return response(ProductStatusCode.PRODUCT_NOT_FOUND)
81
+
82
+    # 产品是否使用
83
+    if product.code_status:
84
+        return response(ProductStatusCode.PRODUCT_HAS_USED)
85
+
86
+    # 产品使用
87
+    product.code_status = True
88
+    product.integral_status = True
89
+    product.franchiser_id = clerk.franchiser_id
90
+    product.clerk_id = clerk.clerk_id
91
+    product.consumer_name = name
92
+    product.consumer_sex = sex
93
+    product.consumer_age = age
94
+    product.consumer_phone = phone
95
+    product.save()
96
+
97
+    # 店员积分
98
+    clerk.integral += product.integral
99
+    clerk.save()
100
+
101
+    # 店员积分记录
102
+    SaleclerkIntegralIncomeExpensesInfo.objects.create(
103
+        franchiser_id=clerk.franchiser_id,
104
+        clerk_id=clerk.clerk_id,
105
+        type=SaleclerkIntegralIncomeExpensesInfo.INCOME,
106
+        code=code,
107
+        integral=product.integral,
108
+        left_integral=clerk.integral,
109
+    )
110
+
111
+    return response(200, 'Submit Success', u'提交成功', {})

BIN
page/sale_views.pyc


+ 74 - 0
page/templates/page/clerk_info.html

@@ -0,0 +1,74 @@
1
+{% load staticfiles %}
2
+
3
+<!DOCTYPE html>
4
+<html lang="zh-CN">
5
+    <head>
6
+        <meta charset="utf-8">
7
+        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
8
+        <meta name="format-detection" content="telephone=no,email=no,address=no">
9
+        <meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no">
10
+        <title>店员销售</title>
11
+
12
+        <link href="https://res.wx.qq.com/open/libs/weui/0.4.3/weui.min.css" rel="stylesheet" type="text/css" />
13
+
14
+        <style>
15
+            input:required:invalid {
16
+                color: #E64340;
17
+            }
18
+            input:required:valid {
19
+                color: rgb(0, 0, 0);
20
+            }
21
+        </style>
22
+    </head>
23
+    <body>
24
+        <div class="container" >
25
+            <div class="weui_cells_title">基本信息</div>
26
+            <div class="weui_cells weui_cells_form">
27
+                <div class="weui_cell">
28
+                    <div class="weui_cell_hd"><label for="" class="weui_label">姓名</label></div>
29
+                    <div class="weui_cell_bd weui_cell_primary">
30
+                        <input id="chiser" class="weui_input" type="text" value="{{ clerk_info.franchiser_name }}" disabled>
31
+                    </div>
32
+                </div>
33
+                <div class="weui_cell">
34
+                    <div class="weui_cell_hd"><label for="" class="weui_label">姓名</label></div>
35
+                    <div class="weui_cell_bd weui_cell_primary">
36
+                        <input id="name" class="weui_input" type="text" value="{{ clerk_info.clerk_name }}" disabled>
37
+                    </div>
38
+                </div>
39
+                <div class="weui_cell">
40
+                    <div class="weui_cell_hd"><label for="" class="weui_label">姓名</label></div>
41
+                    <div class="weui_cell_bd weui_cell_primary">
42
+                        <input id="sex" class="weui_input" type="text" value="{% ifequal clerk_info.clerk_sex 1 %}男{% else %}女{% endifequal %}" disabled>
43
+                    </div>
44
+                </div>
45
+                <div class="weui_cell">
46
+                    <div class="weui_cell_hd"><label for="" class="weui_label">手机号</label></div>
47
+                    <div class="weui_cell_bd weui_cell_primary">
48
+                        <input id="phone" class="weui_input" type="text" required="required" pattern="[0-9]{11}" value="{{ clerk_info.clerk_phone }}" disabled>
49
+                    </div>
50
+                </div>
51
+                <div class="weui_cell">
52
+                    <div class="weui_cell_hd"><label for="" class="weui_label">积分</label></div>
53
+                    <div class="weui_cell_bd weui_cell_primary">
54
+                        <input id="integral" class="weui_input" type="text" required="required" pattern="[0-9]{11}" value="{{ clerk_info.integral }}" disabled>
55
+                    </div>
56
+                </div>
57
+            </div>
58
+        </div>
59
+
60
+        <script src="//cdn.bootcss.com/zepto/1.1.6/zepto.min.js"></script>
61
+        <script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>
62
+        <script type="text/javascript" src="{% static 'tamron/js/jswe.js' %}?v=1"></script>
63
+        <script>
64
+            V.initWxData({
65
+                imgUrl: "http://pai.ai/static/pai2/img/paiai_96_96.png",
66
+                link: 'http://api.pai.ai/wx_oauth2?redirect_url=http://pai.ai/page/lensman&scope=snsapi_base',
67
+                desc: "摄影师授权",
68
+                title: "摄影师授权",
69
+                timeLine: ""
70
+            }, true);
71
+            V.hideOptionMenu();
72
+        </script>
73
+    </body>
74
+</html>

+ 198 - 0
page/templates/page/clerk_oauth.html

@@ -0,0 +1,198 @@
1
+{% load staticfiles %}
2
+
3
+<!DOCTYPE html>
4
+<html lang="zh-CN">
5
+    <head>
6
+        <meta charset="utf-8">
7
+        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
8
+        <meta name="format-detection" content="telephone=no,email=no,address=no">
9
+        <meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no">
10
+        <title>店员授权</title>
11
+
12
+        <link href="https://res.wx.qq.com/open/libs/weui/0.4.3/weui.min.css" rel="stylesheet" type="text/css" />
13
+
14
+        <style>
15
+            input:required:invalid {
16
+                color: #E64340;
17
+            }
18
+            input:required:valid {
19
+                color: rgb(0, 0, 0);
20
+            }
21
+        </style>
22
+    </head>
23
+    <body>
24
+        <div class="container" >
25
+            <div class="weui_cells_title">基本信息</div>
26
+            <div class="weui_cells weui_cells_form">
27
+                <div class="weui_cell weui_cell_select weui_select_after">
28
+                    <div class="weui_cell_hd"><label for="" class="weui_label">经销商</label></div>
29
+                    <div class="weui_cell_bd weui_cell_primary">
30
+                        <select id="chiser" class="weui_select" name="select" {% if not modified %}disabled{% endif %}>
31
+                            {% for chiser in chisers %}
32
+                            <option value="{{ chiser.franchiser_id }}" {% ifequal chiser.franchiser_id clerk_info.franchiser_id %}selected{% endifequal %}>{{ chiser.franchiser_name }}</option>
33
+                            {% endfor %}
34
+                        </select>
35
+                    </div>
36
+                </div>
37
+                <div class="weui_cell">
38
+                    <div class="weui_cell_hd"><label for="" class="weui_label">姓名</label></div>
39
+                    <div class="weui_cell_bd weui_cell_primary">
40
+                        <input id="name" class="weui_input" type="text" value="{{ clerk_info.clerk_name }}" placeholder="请输入姓名" {% if not modified %}disabled{% endif %}>
41
+                    </div>
42
+                </div>
43
+                <div class="weui_cell weui_cell_select weui_select_after">
44
+                    <div class="weui_cell_hd"><label for="" class="weui_label">性别</label></div>
45
+                    <div class="weui_cell_bd weui_cell_primary">
46
+                        <select id="sex" class="weui_select" name="select" {% if not modified %}disabled{% endif %}>
47
+                            <option value="1" {% ifequal clerk_info.clerk_sex 1 %}selected{% endifequal %}>男</option>
48
+                            <option value="0" {% ifequal clerk_info.clerk_sex 0 %}selected{% endifequal %}>女</option>
49
+                        </select>
50
+                    </div>
51
+                </div>
52
+                <div class="weui_cell">
53
+                    <div class="weui_cell_hd"><label for="" class="weui_label">手机号</label></div>
54
+                    <div class="weui_cell_bd weui_cell_primary">
55
+                        <input id="phone" class="weui_input" type="text" required="required" pattern="[0-9]{11}" value="{{ clerk_info.clerk_phone }}" placeholder="请输入手机号" {% if not modified %}disabled{% endif %}>
56
+                    </div>
57
+                </div>
58
+            </div>
59
+
60
+            {% if clerk_info %}
61
+            <div class="weui_cells_title">审核状态</div>
62
+            <div class="weui_cells">
63
+                <div class="weui_cell">
64
+                    <div class="weui_cell_bd weui_cell_primary">
65
+                        <p>状态</p>
66
+                    </div>
67
+                    <div class="weui_cell_ft">
68
+                        {% ifequal clerk_info.status -1 %}已拒绝{% endifequal %}
69
+                        {% ifequal clerk_info.status 0 %}审核中{% endifequal %}
70
+                        {% ifequal clerk_info.status 1 %}已激活{% endifequal %}
71
+                        {% ifequal clerk_info.status 2 %}已禁用{% endifequal %}
72
+                        {% ifequal clerk_info.status 3 %}已删除{% endifequal %}
73
+                    </div>
74
+                </div>
75
+            </div>
76
+            {% endif %}
77
+
78
+
79
+            {% ifequal clerk_info.status -1 %}
80
+            <div class="weui_cells_title">拒绝原因</div>
81
+            <div class="weui_cells">
82
+                <div class="weui_panel_bd">
83
+                    <div class="weui_media_box weui_media_text">
84
+                        <p class="weui_media_desc">{{ clerk_info.refused_reason|safe|linebreaks }}</p>
85
+                    </div>
86
+                </div>
87
+            </div>
88
+            {% endifequal %}
89
+
90
+            <br>
91
+
92
+            {% if modified %}<button id="submit" class="weui_btn weui_btn_warn">确认</button>{% endif %}
93
+
94
+            <div class="weui_dialog_alert" id="dialog" style="display: none">
95
+                <div class="weui_mask"></div>
96
+                <div class="weui_dialog">
97
+                    <div class="weui_dialog_hd"><strong id="title" class="weui_dialog_title">弹窗标题</strong></div>
98
+                    <div id="content" class="weui_dialog_bd">弹窗内容,告知当前页面信息等</div>
99
+                    <div class="weui_dialog_ft">
100
+                        <a href="javascript:;" class="weui_btn_dialog primary">确定</a>
101
+                    </div>
102
+                </div>
103
+            </div>
104
+
105
+            <div id="toast" style="display: none;">
106
+                <div class="weui_mask_transparent"></div>
107
+                <div class="weui_toast">
108
+                    <i class="weui_icon_toast"></i>
109
+                    <p class="weui_toast_content">已完成</p>
110
+                </div>
111
+            </div>
112
+        </div>
113
+
114
+        <script src="//cdn.bootcss.com/zepto/1.1.6/zepto.min.js"></script>
115
+        <script>
116
+            {% if modified %}
117
+            $(function() {
118
+                function getURLParameter(name) {
119
+                  return decodeURIComponent((new RegExp('[?|&]' + name + '=' + '([^&;]+?)(&|#|;|$)').exec(location.search) || [null, ''])[1].replace(/\+/g, '%20')) || null;
120
+                }
121
+
122
+                function show_error_dialog(title, content) {
123
+                    $('#dialog #title').text(title);
124
+                    $('#dialog #content').text(content);
125
+                    $('#dialog').show();
126
+                }
127
+
128
+                function data_check() {
129
+                    var unionid = getURLParameter('unionid');
130
+                    if (!unionid) {
131
+                        show_error_dialog('微信授权', '微信授权失败,请重新打开页面');
132
+                        return false;
133
+                    }
134
+
135
+                    var name = $('#name').val();
136
+                    if (!name) {
137
+                        show_error_dialog('姓名', '姓名错误,请检查重新输入');
138
+                        return false;
139
+                    }
140
+
141
+                    var phone_valid = $('#phone').is(':valid');
142
+                    if (!phone_valid) {
143
+                        show_error_dialog('手机号', '手机号错误,请检查重新输入');
144
+                        return false;
145
+                    }
146
+
147
+                    return {
148
+                        unionid: unionid,
149
+                        openid: getURLParameter('openid'),
150
+                        chiser: $('#chiser option:checked').val(),
151
+                        name: name,
152
+                        sex: $('#sex option:checked').val(),
153
+                        phone: $('#phone').val(),
154
+                    }
155
+                }
156
+
157
+                $('#submit').click(function () {
158
+                    var check_result = data_check();
159
+                    if (check_result){
160
+                        $.ajax({
161
+                            type: 'POST',
162
+                            url: '{{ domain }}api/clerk/submit',
163
+                            data: check_result,
164
+                            success: function(data) {
165
+                                if (data.status == 200) {
166
+                                    $('#toast').show();
167
+                                    setTimeout(function () {
168
+                                        $('#toast').hide();
169
+                                    }, 1000);
170
+                                    window.location.reload();
171
+                                } else {
172
+                                    show_error_dialog('错误', data.description);
173
+                                }
174
+                            }
175
+                        })
176
+                    }
177
+                });
178
+
179
+                $('#dialog .weui_btn_dialog').click(function () {
180
+                    $('#dialog').hide();
181
+                })
182
+            });
183
+            {% endif %}
184
+        </script>
185
+        <script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>
186
+        <script type="text/javascript" src="{% static 'tamron/js/jswe.js' %}?v=1"></script>
187
+        <script>
188
+            V.initWxData({
189
+                imgUrl: "http://pai.ai/static/pai2/img/paiai_96_96.png",
190
+                link: 'http://api.pai.ai/wx_oauth2?redirect_url=http://pai.ai/page/lensman&scope=snsapi_base',
191
+                desc: "摄影师授权",
192
+                title: "摄影师授权",
193
+                timeLine: ""
194
+            }, true);
195
+            V.hideOptionMenu();
196
+        </script>
197
+    </body>
198
+</html>

+ 187 - 0
page/templates/page/clerk_sale.html

@@ -0,0 +1,187 @@
1
+{% load staticfiles %}
2
+
3
+<!DOCTYPE html>
4
+<html lang="zh-CN">
5
+    <head>
6
+        <meta charset="utf-8">
7
+        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
8
+        <meta name="format-detection" content="telephone=no,email=no,address=no">
9
+        <meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no">
10
+        <title>店员销售</title>
11
+
12
+        <link href="https://res.wx.qq.com/open/libs/weui/0.4.3/weui.min.css" rel="stylesheet" type="text/css" />
13
+
14
+        <style>
15
+            input:required:invalid {
16
+                color: #E64340;
17
+            }
18
+            input:required:valid {
19
+                color: rgb(0, 0, 0);
20
+            }
21
+        </style>
22
+    </head>
23
+    <body>
24
+        <div class="container" >
25
+            <div class="weui_cells_title">机器信息</div>
26
+            <div class="weui_cells weui_cells_form">
27
+                <div class="weui_cell weui_cell_select weui_select_after">
28
+                    <div class="weui_cell_hd"><label for="" class="weui_label">型号</label></div>
29
+                    <div class="weui_cell_bd weui_cell_primary">
30
+                        <select id="model" class="weui_select" name="select">
31
+                            {% for model in models %}
32
+                            <option value="{{ model.model_id }}">{{ model.model_name }}</option>
33
+                            {% endfor %}
34
+                        </select>
35
+                    </div>
36
+                </div>
37
+                <div class="weui_cell">
38
+                    <div class="weui_cell_hd"><label for="" class="weui_label">机身码</label></div>
39
+                    <div class="weui_cell_bd weui_cell_primary">
40
+                        <input id="code" class="weui_input" type="text" value="" placeholder="请输入机身码">
41
+                    </div>
42
+                </div>
43
+            </div>
44
+
45
+            <div class="weui_cells_title">消费者信息</div>
46
+            <div class="weui_cells weui_cells_form">
47
+                <div class="weui_cell">
48
+                    <div class="weui_cell_hd"><label for="" class="weui_label">姓名</label></div>
49
+                    <div class="weui_cell_bd weui_cell_primary">
50
+                        <input id="name" class="weui_input" type="text" value="" placeholder="请输入消费者姓名">
51
+                    </div>
52
+                </div>
53
+                <div class="weui_cell weui_cell_select weui_select_after">
54
+                    <div class="weui_cell_hd"><label for="" class="weui_label">性别</label></div>
55
+                    <div class="weui_cell_bd weui_cell_primary">
56
+                        <select id="sex" class="weui_select" name="select">
57
+                            <option value="1">男</option>
58
+                            <option value="0">女</option>
59
+                        </select>
60
+                    </div>
61
+                </div>
62
+                <div class="weui_cell weui_cell_select weui_select_after">
63
+                    <div class="weui_cell_hd"><label for="" class="weui_label">年龄</label></div>
64
+                    <div class="weui_cell_bd weui_cell_primary">
65
+                        <select id="age" class="weui_select" name="select">
66
+                            <option value="1">18周岁以下</option>
67
+                            <option value="2">60周岁以上</option>
68
+                        </select>
69
+                    </div>
70
+                </div>
71
+                <div class="weui_cell">
72
+                    <div class="weui_cell_hd"><label for="" class="weui_label">手机号</label></div>
73
+                    <div class="weui_cell_bd weui_cell_primary">
74
+                        <input id="phone" class="weui_input" type="text" required="required" pattern="[0-9]{11}" value="" placeholder="请输入消费者手机号">
75
+                    </div>
76
+                </div>
77
+            </div>
78
+
79
+            <br>
80
+
81
+            <button id="submit" class="weui_btn weui_btn_warn">确认</button>
82
+
83
+            <div class="weui_dialog_alert" id="dialog" style="display: none">
84
+                <div class="weui_mask"></div>
85
+                <div class="weui_dialog">
86
+                    <div class="weui_dialog_hd"><strong id="title" class="weui_dialog_title">弹窗标题</strong></div>
87
+                    <div id="content" class="weui_dialog_bd">弹窗内容,告知当前页面信息等</div>
88
+                    <div class="weui_dialog_ft">
89
+                        <a href="javascript:;" class="weui_btn_dialog primary">确定</a>
90
+                    </div>
91
+                </div>
92
+            </div>
93
+
94
+            <div id="toast" style="display: none;">
95
+                <div class="weui_mask_transparent"></div>
96
+                <div class="weui_toast">
97
+                    <i class="weui_icon_toast"></i>
98
+                    <p class="weui_toast_content">已完成</p>
99
+                </div>
100
+            </div>
101
+        </div>
102
+
103
+        <script src="//cdn.bootcss.com/zepto/1.1.6/zepto.min.js"></script>
104
+        <script>
105
+            $(function() {
106
+                function show_error_dialog(title, content) {
107
+                    $('#dialog #title').text(title);
108
+                    $('#dialog #content').text(content);
109
+                    $('#dialog').show();
110
+                }
111
+
112
+                function data_check() {
113
+                    var clerk_id = "{{ clerk_info.clerk_id }}";
114
+                    if (!clerk_id) {
115
+                        show_error_dialog('微信授权', '微信授权失败,请重新打开页面');
116
+                        return false;
117
+                    }
118
+
119
+                    var code = $('#code').val();
120
+                    if (!code) {
121
+                        show_error_dialog('机身码', '机身码错误,请检查重新输入');
122
+                        return false;
123
+                    }
124
+
125
+                    var name = $('#name').val();
126
+                    if (!name) {
127
+                        show_error_dialog('姓名', '姓名错误,请检查重新输入');
128
+                        return false;
129
+                    }
130
+
131
+                    var phone_valid = $('#phone').is(':valid');
132
+                    if (!phone_valid) {
133
+                        show_error_dialog('手机号', '手机号错误,请检查重新输入');
134
+                        return false;
135
+                    }
136
+
137
+                    return {
138
+                        clerk_id: clerk_id,
139
+                        model_id: $('#model option:checked').val(),
140
+                        code: code,
141
+                        name: name,
142
+                        sex: $('#sex option:checked').val(),
143
+                        age: $('#age option:checked').val(),
144
+                        phone: $('#phone').val(),
145
+                    }
146
+                }
147
+
148
+                $('#submit').click(function () {
149
+                    var check_result = data_check();
150
+                    if (check_result){
151
+                        $.ajax({
152
+                            type: 'POST',
153
+                            url: '{{ domain }}api/clerk/sale/submit',
154
+                            data: check_result,
155
+                            success: function(data) {
156
+                                if (data.status == 200) {
157
+                                    $('#toast').show();
158
+                                    setTimeout(function () {
159
+                                        $('#toast').hide();
160
+                                    }, 1000);
161
+                                } else {
162
+                                    show_error_dialog('错误', data.description);
163
+                                }
164
+                            }
165
+                        })
166
+                    }
167
+                });
168
+
169
+                $('#dialog .weui_btn_dialog').click(function () {
170
+                    $('#dialog').hide();
171
+                })
172
+            });
173
+        </script>
174
+        <script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>
175
+        <script type="text/javascript" src="{% static 'tamron/js/jswe.js' %}?v=1"></script>
176
+        <script>
177
+            V.initWxData({
178
+                imgUrl: "http://pai.ai/static/pai2/img/paiai_96_96.png",
179
+                link: 'http://api.pai.ai/wx_oauth2?redirect_url=http://pai.ai/page/lensman&scope=snsapi_base',
180
+                desc: "摄影师授权",
181
+                title: "摄影师授权",
182
+                timeLine: ""
183
+            }, true);
184
+            V.hideOptionMenu();
185
+        </script>
186
+    </body>
187
+</html>

+ 4 - 0
page/tests.py

@@ -0,0 +1,4 @@
1
+from django.test import TestCase
2
+
3
+
4
+# Create your tests here.

+ 4 - 0
page/views.py

@@ -0,0 +1,4 @@
1
+from django.shortcuts import render
2
+
3
+
4
+# Create your views here.

BIN
page/views.pyc


+ 9 - 0
pep8.sh

@@ -0,0 +1,9 @@
1
+#!/bin/bash
2
+
3
+# Ignoring autogenerated files
4
+#  -- Migration directories
5
+# Ignoring error codes
6
+#  -- E128 continuation line under-indented for visual indent
7
+#  -- E501 line too long
8
+
9
+pep8 --exclude=migrations --ignore=E128,E501 .

+ 0 - 0
product/__init__.py


BIN
product/__init__.pyc


+ 29 - 0
product/admin.py

@@ -0,0 +1,29 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+from django.contrib import admin
4
+
5
+from product.models import ProductCodeSubmitLogInfo, ProductInfo, ProductModelInfo
6
+
7
+
8
+class ProductModelInfoAdmin(admin.ModelAdmin):
9
+    readonly_fields = ('model_id', )
10
+    list_display = ('model_id', 'model_name', 'integral', 'status', 'created_at', 'updated_at')
11
+    search_fields = ('model_id', 'model_name')
12
+    list_filter = ('status', )
13
+
14
+
15
+class ProductInfoAdmin(admin.ModelAdmin):
16
+    list_display = ('model_id', 'model_name', 'code', 'code_status', 'integral', 'integral_status', 'franchiser_id', 'clerk_id', 'consumer_name', 'consumer_sex', 'consumer_age', 'consumer_phone', 'status', 'created_at', 'updated_at')
17
+    search_fields = ('model_id', 'model_name', 'code', 'consumer_name', 'consumer_phone')
18
+    list_filter = ('code_status', 'integral_status', 'franchiser_id', 'consumer_sex', 'status')
19
+
20
+
21
+class ProductCodeSubmitLogInfoAdmin(admin.ModelAdmin):
22
+    list_display = ('model_id', 'model_name', 'code', 'franchiser_id', 'clerk_id', 'consumer_name', 'consumer_sex', 'consumer_age', 'consumer_phone', 'status', 'created_at', 'updated_at')
23
+    search_fields = ('model_id', 'model_name', 'code', 'consumer_name', 'consumer_phone')
24
+    list_filter = ('franchiser_id', 'consumer_sex', 'status')
25
+
26
+
27
+admin.site.register(ProductModelInfo, ProductModelInfoAdmin)
28
+admin.site.register(ProductInfo, ProductInfoAdmin)
29
+admin.site.register(ProductCodeSubmitLogInfo, ProductCodeSubmitLogInfoAdmin)

BIN
product/admin.pyc


+ 77 - 0
product/migrations/0001_initial.py

@@ -0,0 +1,77 @@
1
+# -*- coding: utf-8 -*-
2
+from __future__ import unicode_literals
3
+
4
+from django.db import models, migrations
5
+import shortuuidfield.fields
6
+
7
+
8
+class Migration(migrations.Migration):
9
+
10
+    dependencies = [
11
+    ]
12
+
13
+    operations = [
14
+        migrations.CreateModel(
15
+            name='ProductCodeSubmitLogInfo',
16
+            fields=[
17
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
18
+                ('status', models.BooleanField(default=True, help_text='\u72b6\u6001', db_index=True, verbose_name='status')),
19
+                ('created_at', models.DateTimeField(help_text='\u521b\u5efa\u65f6\u95f4', verbose_name='created_at', auto_now_add=True)),
20
+                ('updated_at', models.DateTimeField(help_text='\u66f4\u65b0\u65f6\u95f4', verbose_name='updated_at', auto_now=True)),
21
+                ('model_id', models.CharField(max_length=255, blank=True, help_text='\u578b\u53f7\u552f\u4e00\u6807\u8bc6', null=True, verbose_name='model_id', db_index=True)),
22
+                ('model_name', models.CharField(max_length=255, blank=True, help_text='\u578b\u53f7\u540d\u79f0', null=True, verbose_name='model_name', db_index=True)),
23
+                ('code', models.CharField(help_text='\u673a\u8eab\u7801', max_length=255, null=True, verbose_name='code', blank=True)),
24
+                ('franchiser_id', models.CharField(max_length=255, blank=True, help_text='\u7ecf\u9500\u5546\u552f\u4e00\u6807\u8bc6', null=True, verbose_name='franchiser_id', db_index=True)),
25
+                ('clerk_id', models.CharField(max_length=255, blank=True, help_text='\u5e97\u5458\u552f\u4e00\u6807\u8bc6', null=True, verbose_name='clerk_id', db_index=True)),
26
+                ('consumer_name', models.CharField(help_text='\u6d88\u8d39\u8005\u540d\u79f0', max_length=255, null=True, verbose_name='consumer_name', blank=True)),
27
+                ('consumer_sex', models.IntegerField(default=1, help_text='\u6d88\u8d39\u8005\u6027\u522b', db_index=True, verbose_name='consumer_sex', choices=[(1, '\u7537'), (0, '\u5973')])),
28
+                ('consumer_age', models.IntegerField(default=0, help_text='\u6d88\u8d39\u8005\u5e74\u9f84', verbose_name='consumer_age')),
29
+                ('consumer_phone', models.CharField(help_text='\u6d88\u8d39\u8005\u8054\u7cfb\u7535\u8bdd', max_length=255, null=True, verbose_name='consumer_phone', blank=True)),
30
+            ],
31
+            options={
32
+                'verbose_name': 'productcodesubmitloginfo',
33
+                'verbose_name_plural': 'productcodesubmitloginfo',
34
+            },
35
+        ),
36
+        migrations.CreateModel(
37
+            name='ProductInfo',
38
+            fields=[
39
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
40
+                ('status', models.BooleanField(default=True, help_text='\u72b6\u6001', db_index=True, verbose_name='status')),
41
+                ('created_at', models.DateTimeField(help_text='\u521b\u5efa\u65f6\u95f4', verbose_name='created_at', auto_now_add=True)),
42
+                ('updated_at', models.DateTimeField(help_text='\u66f4\u65b0\u65f6\u95f4', verbose_name='updated_at', auto_now=True)),
43
+                ('model_id', models.CharField(max_length=255, blank=True, help_text='\u578b\u53f7\u552f\u4e00\u6807\u8bc6', null=True, verbose_name='model_id', db_index=True)),
44
+                ('model_name', models.CharField(max_length=255, blank=True, help_text='\u578b\u53f7\u540d\u79f0', null=True, verbose_name='model_name', db_index=True)),
45
+                ('code', models.CharField(help_text='\u673a\u8eab\u7801', max_length=255, null=True, verbose_name='code', blank=True)),
46
+                ('code_status', models.BooleanField(default=False, help_text='\u673a\u8eab\u7801\u72b6\u6001', db_index=True, verbose_name='code_status')),
47
+                ('integral', models.IntegerField(default=0, help_text='\u79ef\u5206', verbose_name='integral')),
48
+                ('integral_status', models.BooleanField(default=False, help_text='\u79ef\u5206\u72b6\u6001', db_index=True, verbose_name='integral_status')),
49
+                ('franchiser_id', models.CharField(max_length=255, blank=True, help_text='\u7ecf\u9500\u5546\u552f\u4e00\u6807\u8bc6', null=True, verbose_name='franchiser_id', db_index=True)),
50
+                ('clerk_id', models.CharField(max_length=255, blank=True, help_text='\u5e97\u5458\u552f\u4e00\u6807\u8bc6', null=True, verbose_name='clerk_id', db_index=True)),
51
+                ('consumer_name', models.CharField(help_text='\u6d88\u8d39\u8005\u540d\u79f0', max_length=255, null=True, verbose_name='consumer_name', blank=True)),
52
+                ('consumer_sex', models.IntegerField(default=1, help_text='\u6d88\u8d39\u8005\u6027\u522b', db_index=True, verbose_name='consumer_sex', choices=[(1, '\u7537'), (0, '\u5973')])),
53
+                ('consumer_age', models.IntegerField(default=0, help_text='\u6d88\u8d39\u8005\u5e74\u9f84', verbose_name='consumer_age')),
54
+                ('consumer_phone', models.CharField(help_text='\u6d88\u8d39\u8005\u8054\u7cfb\u7535\u8bdd', max_length=255, null=True, verbose_name='consumer_phone', blank=True)),
55
+            ],
56
+            options={
57
+                'verbose_name': 'productinfo',
58
+                'verbose_name_plural': 'productinfo',
59
+            },
60
+        ),
61
+        migrations.CreateModel(
62
+            name='ProductModelInfo',
63
+            fields=[
64
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
65
+                ('status', models.BooleanField(default=True, help_text='\u72b6\u6001', db_index=True, verbose_name='status')),
66
+                ('created_at', models.DateTimeField(help_text='\u521b\u5efa\u65f6\u95f4', verbose_name='created_at', auto_now_add=True)),
67
+                ('updated_at', models.DateTimeField(help_text='\u66f4\u65b0\u65f6\u95f4', verbose_name='updated_at', auto_now=True)),
68
+                ('model_id', shortuuidfield.fields.ShortUUIDField(editable=False, max_length=22, blank=True, help_text='\u578b\u53f7\u552f\u4e00\u6807\u8bc6', unique=True, db_index=True)),
69
+                ('model_name', models.CharField(help_text='\u578b\u53f7\u540d\u79f0', max_length=255, null=True, verbose_name='model_name', blank=True)),
70
+                ('integral', models.IntegerField(default=0, help_text='\u578b\u53f7\u79ef\u5206', verbose_name='integral')),
71
+            ],
72
+            options={
73
+                'verbose_name': '\u4ea7\u54c1\u578b\u53f7\u4fe1\u606f',
74
+                'verbose_name_plural': '\u4ea7\u54c1\u578b\u53f7\u4fe1\u606f',
75
+            },
76
+        ),
77
+    ]

BIN
product/migrations/0001_initial.pyc


+ 24 - 0
product/migrations/0002_auto_20170619_1734.py

@@ -0,0 +1,24 @@
1
+# -*- coding: utf-8 -*-
2
+from __future__ import unicode_literals
3
+
4
+from django.db import models, migrations
5
+
6
+
7
+class Migration(migrations.Migration):
8
+
9
+    dependencies = [
10
+        ('product', '0001_initial'),
11
+    ]
12
+
13
+    operations = [
14
+        migrations.AlterField(
15
+            model_name='productinfo',
16
+            name='code_status',
17
+            field=models.BooleanField(default=False, help_text='\u673a\u8eab\u7801\u72b6\u6001, True\u5df2\u4f7f\u7528\uff0cFalse\u672a\u4f7f\u7528', db_index=True, verbose_name='code_status'),
18
+        ),
19
+        migrations.AlterField(
20
+            model_name='productinfo',
21
+            name='integral_status',
22
+            field=models.BooleanField(default=False, help_text='\u79ef\u5206\u72b6\u6001, True\u5df2\u79ef\u5206\uff0cFalse\u672a\u79ef\u5206', db_index=True, verbose_name='integral_status'),
23
+        ),
24
+    ]

BIN
product/migrations/0002_auto_20170619_1734.pyc


+ 0 - 0
product/migrations/__init__.py


BIN
product/migrations/__init__.pyc


+ 99 - 0
product/models.py

@@ -0,0 +1,99 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+from django.db import models
4
+from django.utils.translation import ugettext_lazy as _
5
+from shortuuidfield import ShortUUIDField
6
+
7
+from tamron.basemodels import CreateUpdateMixin
8
+
9
+
10
+class ProductModelInfo(CreateUpdateMixin):
11
+    model_id = ShortUUIDField(_(u'model_id'), max_length=255, help_text=u'型号唯一标识', db_index=True, unique=True)
12
+    model_name = models.CharField(_(u'model_name'), max_length=255, blank=True, null=True, help_text=u'型号名称')
13
+    integral = models.IntegerField(_(u'integral'), default=0, help_text=u'型号积分')
14
+
15
+    class Meta:
16
+        verbose_name = _(u'产品型号信息')
17
+        verbose_name_plural = _(u'产品型号信息')
18
+
19
+    def __unicode__(self):
20
+        return unicode(self.pk)
21
+
22
+    @property
23
+    def data(self):
24
+        return {
25
+            'model_id': self.model_id,
26
+            'model_name': self.model_name,
27
+            'integral': self.integral,
28
+        }
29
+
30
+
31
+class ProductInfo(CreateUpdateMixin):
32
+    MALE = 1
33
+    FEMALE = 0
34
+
35
+    SEX_TYPE = (
36
+        (MALE, u'男'),
37
+        (FEMALE, u'女'),
38
+    )
39
+
40
+    model_id = models.CharField(_(u'model_id'), max_length=255, blank=True, null=True, help_text=u'型号唯一标识', db_index=True)
41
+    model_name = models.CharField(_(u'model_name'), max_length=255, blank=True, null=True, help_text=u'型号名称', db_index=True)
42
+
43
+    code = models.CharField(_(u'code'), max_length=255, blank=True, null=True, help_text=u'机身码')
44
+    code_status = models.BooleanField(_(u'code_status'), default=False, help_text=u'机身码状态, True已使用,False未使用', db_index=True)
45
+
46
+    integral = models.IntegerField(_(u'integral'), default=0, help_text=u'积分')
47
+    integral_status = models.BooleanField(_(u'integral_status'), default=False, help_text=u'积分状态, True已积分,False未积分', db_index=True)
48
+
49
+    franchiser_id = models.CharField(_(u'franchiser_id'), max_length=255, blank=True, null=True, help_text=u'经销商唯一标识', db_index=True)
50
+    clerk_id = models.CharField(_(u'clerk_id'), max_length=255, blank=True, null=True, help_text=u'店员唯一标识', db_index=True)
51
+
52
+    consumer_name = models.CharField(_(u'consumer_name'), max_length=255, blank=True, null=True, help_text=u'消费者名称')
53
+    consumer_sex = models.IntegerField(_(u'consumer_sex'), choices=SEX_TYPE, default=MALE, help_text=u'消费者性别', db_index=True)
54
+    consumer_age = models.IntegerField(_(u'consumer_age'), default=0, help_text=u'消费者年龄')
55
+    consumer_phone = models.CharField(_(u'consumer_phone'), max_length=255, blank=True, null=True, help_text=u'消费者联系电话')
56
+
57
+    class Meta:
58
+        verbose_name = _(u'productinfo')
59
+        verbose_name_plural = _(u'productinfo')
60
+
61
+    def __unicode__(self):
62
+        return unicode(self.pk)
63
+
64
+    @property
65
+    def data(self):
66
+        return {
67
+            'model_id': self.model_id,
68
+            'model_name': self.model_name,
69
+            'code': self.code,
70
+        }
71
+
72
+
73
+class ProductCodeSubmitLogInfo(CreateUpdateMixin):
74
+    MALE = 1
75
+    FEMALE = 0
76
+
77
+    SEX_TYPE = (
78
+        (MALE, u'男'),
79
+        (FEMALE, u'女'),
80
+    )
81
+
82
+    model_id = models.CharField(_(u'model_id'), max_length=255, blank=True, null=True, help_text=u'型号唯一标识', db_index=True)
83
+    model_name = models.CharField(_(u'model_name'), max_length=255, blank=True, null=True, help_text=u'型号名称', db_index=True)
84
+    code = models.CharField(_(u'code'), max_length=255, blank=True, null=True, help_text=u'机身码')
85
+
86
+    franchiser_id = models.CharField(_(u'franchiser_id'), max_length=255, blank=True, null=True, help_text=u'经销商唯一标识', db_index=True)
87
+    clerk_id = models.CharField(_(u'clerk_id'), max_length=255, blank=True, null=True, help_text=u'店员唯一标识', db_index=True)
88
+
89
+    consumer_name = models.CharField(_(u'consumer_name'), max_length=255, blank=True, null=True, help_text=u'消费者名称')
90
+    consumer_sex = models.IntegerField(_(u'consumer_sex'), choices=SEX_TYPE, default=MALE, help_text=u'消费者性别', db_index=True)
91
+    consumer_age = models.IntegerField(_(u'consumer_age'), default=0, help_text=u'消费者年龄')
92
+    consumer_phone = models.CharField(_(u'consumer_phone'), max_length=255, blank=True, null=True, help_text=u'消费者联系电话')
93
+
94
+    class Meta:
95
+        verbose_name = _(u'productcodesubmitloginfo')
96
+        verbose_name_plural = _(u'productcodesubmitloginfo')
97
+
98
+    def __unicode__(self):
99
+        return unicode(self.pk)

BIN
product/models.pyc


+ 4 - 0
product/tests.py

@@ -0,0 +1,4 @@
1
+from django.test import TestCase
2
+
3
+
4
+# Create your tests here.

+ 4 - 0
product/views.py

@@ -0,0 +1,4 @@
1
+from django.shortcuts import render
2
+
3
+
4
+# Create your views here.

+ 39 - 0
requirements.txt

@@ -0,0 +1,39 @@
1
+-e git+https://github.com/Brightcells/django-q.git#egg=django-q
2
+-e git+https://github.com/andymccurdy/redis-py.git#egg=redis-py
3
+CodeConvert==2.0.4
4
+Django==1.8.4
5
+MySQL-python==1.2.5
6
+Pillow==3.4.2
7
+StatusCode==1.0.0
8
+TimeConvert==1.4.1
9
+cryptography==1.5.2
10
+django-curtail-uuid==1.0.0
11
+django-detect==1.0.5
12
+django-file-md5==1.0.1
13
+django-ip==1.0.0
14
+django-json-response==1.1.4
15
+django-logit==1.0.6
16
+django-multidomain==1.1.4
17
+django-paginator2==1.0.3
18
+django-rlog==1.0.7
19
+django-shortuuidfield==0.1.3
20
+django-six==1.0.2
21
+djangorestframework==3.6.3
22
+furl==1.0.0
23
+hiredis==0.2.0
24
+isoweek==1.3.3
25
+jsonfield==2.0.2
26
+mock==2.0.0
27
+pep8==1.7.0
28
+pysnippets==1.0.4
29
+pywe-miniapp==1.0.0
30
+pywe-oauth==1.0.3
31
+pywe-response==1.0.1
32
+qiniu==7.1.4
33
+redis-extensions==1.0.50
34
+requests==2.12.4
35
+rlog==0.2
36
+shortuuid==0.5.0
37
+uWSGI==2.0.15
38
+versions==0.10.0
39
+wechatpy==1.2.8

+ 0 - 0
tamron/__init__.py


BIN
tamron/__init__.pyc


+ 13 - 0
tamron/basemodels.py

@@ -0,0 +1,13 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+from django.db import models
4
+from django.utils.translation import ugettext_lazy as _
5
+
6
+
7
+class CreateUpdateMixin(models.Model):
8
+    status = models.BooleanField(_(u'status'), default=True, help_text=_(u'状态'), db_index=True)
9
+    created_at = models.DateTimeField(_(u'created_at'), auto_now_add=True, editable=True, help_text=_(u'创建时间'))
10
+    updated_at = models.DateTimeField(_(u'updated_at'), auto_now=True, editable=True, help_text=_(u'更新时间'))
11
+
12
+    class Meta:
13
+        abstract = True

BIN
tamron/basemodels.pyc


+ 16 - 0
tamron/func_settings.py

@@ -0,0 +1,16 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+import redis_extensions as redis
4
+
5
+
6
+def redis_conf(conf):
7
+    return {
8
+        'host': conf.get('HOST', 'localhost'),
9
+        'port': conf.get('PORT', 6379),
10
+        'password': '{}:{}'.format(conf.get('USER', ''), conf.get('PASSWORD', '')) if conf.get('USER') else '',
11
+        'db': conf.get('db', 0),
12
+    }
13
+
14
+
15
+def redis_connect(conf):
16
+    return redis.StrictRedisExtensions(connection_pool=redis.ConnectionPool(**redis_conf(conf)))

BIN
tamron/func_settings.pyc


+ 29 - 0
tamron/local_settings.py

@@ -0,0 +1,29 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+import os
4
+
5
+
6
+BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
7
+PROJ_DIR = os.path.abspath(os.path.dirname(os.path.abspath(__file__)))
8
+
9
+TEMPLATES = [
10
+    {
11
+        'BACKEND': 'django.template.backends.django.DjangoTemplates',
12
+        'DIRS': [os.path.join(BASE_DIR, 'templates')],
13
+        # 'APP_DIRS': True,
14
+        'OPTIONS': {
15
+            'context_processors': [
16
+                'django.template.context_processors.debug',
17
+                'django.template.context_processors.request',
18
+                'django.contrib.auth.context_processors.auth',
19
+                'django.contrib.messages.context_processors.messages',
20
+            ],
21
+            'loaders': [
22
+                'django.template.loaders.filesystem.Loader',
23
+                'django.template.loaders.app_directories.Loader',
24
+            ],
25
+        },
26
+    },
27
+]
28
+
29
+DOMAIN = 'http://127.0.0.1:9997/'

BIN
tamron/local_settings.pyc


+ 254 - 0
tamron/settings.py

@@ -0,0 +1,254 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+"""
4
+Django settings for tamron project.
5
+
6
+Generated by 'django-admin startproject' using Django 1.8.4.
7
+
8
+For more information on this file, see
9
+https://docs.djangoproject.com/en/1.8/topics/settings/
10
+
11
+For the full list of settings and their values, see
12
+https://docs.djangoproject.com/en/1.8/ref/settings/
13
+"""
14
+
15
+# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
16
+import os
17
+
18
+
19
+BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
20
+PROJ_DIR = os.path.abspath(os.path.dirname(os.path.abspath(__file__)))
21
+
22
+
23
+# Quick-start development settings - unsuitable for production
24
+# See https://docs.djangoproject.com/en/1.8/howto/deployment/checklist/
25
+
26
+# SECURITY WARNING: keep the secret key used in production secret!
27
+SECRET_KEY = '@!_8xi9(8)gj8zvni#)2-arn)4gn^u&coy-0yld0=1r5*ao@4i'
28
+
29
+# SECURITY WARNING: don't run with debug turned on in production!
30
+DEBUG = True
31
+
32
+ALLOWED_HOSTS = []
33
+
34
+
35
+# Application definition
36
+
37
+INSTALLED_APPS = (
38
+    'django.contrib.admin',
39
+    'django.contrib.auth',
40
+    'django.contrib.contenttypes',
41
+    'django.contrib.sessions',
42
+    'django.contrib.messages',
43
+    'django.contrib.staticfiles',
44
+    'api',
45
+    'account',
46
+    'integral',
47
+    'page',
48
+    'product',
49
+)
50
+
51
+MIDDLEWARE_CLASSES = (
52
+    'django.contrib.sessions.middleware.SessionMiddleware',
53
+    'django.middleware.common.CommonMiddleware',
54
+    # 'django.middleware.csrf.CsrfViewMiddleware',
55
+    'django.contrib.auth.middleware.AuthenticationMiddleware',
56
+    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
57
+    'django.contrib.messages.middleware.MessageMiddleware',
58
+    'django.middleware.clickjacking.XFrameOptionsMiddleware',
59
+    'django.middleware.security.SecurityMiddleware',
60
+)
61
+
62
+ROOT_URLCONF = 'tamron.urls'
63
+
64
+TEMPLATES = [
65
+    {
66
+        'BACKEND': 'django.template.backends.django.DjangoTemplates',
67
+        'DIRS': [os.path.join(BASE_DIR, 'templates')],
68
+        # 'APP_DIRS': True,
69
+        'OPTIONS': {
70
+            'context_processors': [
71
+                'django.template.context_processors.debug',
72
+                'django.template.context_processors.request',
73
+                'django.contrib.auth.context_processors.auth',
74
+                'django.contrib.messages.context_processors.messages',
75
+            ],
76
+            'loaders': [
77
+                ('django.template.loaders.cached.Loader', [
78
+                    'django.template.loaders.filesystem.Loader',
79
+                    'django.template.loaders.app_directories.Loader',
80
+                ]),
81
+            ],
82
+        },
83
+    },
84
+]
85
+
86
+WSGI_APPLICATION = 'tamron.wsgi.application'
87
+
88
+
89
+# Database
90
+# https://docs.djangoproject.com/en/1.8/ref/settings/#databases
91
+
92
+DATABASES = {
93
+    'default': {
94
+        'ENGINE': 'django.db.backends.mysql',
95
+        'NAME': 'tamron',
96
+        'USER': 'root',
97
+        'PASSWORD': '',
98
+        'CONN_MAX_AGE': 600,
99
+        'OPTIONS': {
100
+            # Utf8mb4 for Emoji
101
+            #
102
+            # Nickname
103
+            #
104
+            # account.WechatInfo ==> nickname
105
+            #   ALTER TABLE account_wechatinfo MODIFY COLUMN nickname VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
106
+            # account.UserInfo ==> nickname
107
+            #   ALTER TABLE account_userinfo MODIFY COLUMN nickname VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
108
+            # group.GroupUserInfo ==> nickname
109
+            #   ALTER TABLE group_groupuserinfo MODIFY COLUMN nickname VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL;
110
+            # group.GroupPhotoInfo ==> nickname
111
+            #   ALTER TABLE group_groupphotoinfo MODIFY COLUMN nickname VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL;
112
+            # group.PhotoCommentInfo ==> nickname
113
+            #   ALTER TABLE group_photocommentinfo MODIFY COLUMN nickname VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL;
114
+            # group.PhotoThumbUpInfo ==> nickname
115
+            #   ALTER TABLE group_photothumbupinfo MODIFY COLUMN nickname VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL;
116
+            # group.UserMessageInfo ==> nickname
117
+            #   ALTER TABLE message_usermessageinfo MODIFY COLUMN from_nickname VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL;
118
+            #
119
+            # Comment
120
+            # group.PhotoCommentInfo ==> comment
121
+            #   ALTER TABLE group_photocommentinfo MODIFY COLUMN comment LONGTEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
122
+            'charset': 'utf8mb4',
123
+        },
124
+    }
125
+}
126
+
127
+
128
+# Internationalization
129
+# https://docs.djangoproject.com/en/1.8/topics/i18n/
130
+
131
+LANGUAGE_CODE = 'zh-Hans'
132
+
133
+TIME_ZONE = 'Asia/Shanghai'
134
+
135
+USE_I18N = True
136
+
137
+USE_L10N = True
138
+
139
+USE_TZ = True
140
+
141
+
142
+# Static files (CSS, JavaScript, Images)
143
+# https://docs.djangoproject.com/en/1.8/howto/static-files/
144
+
145
+STATICFILES_DIRS = (
146
+    os.path.join(PROJ_DIR, 'static').replace('\\', '/'),
147
+)
148
+
149
+STATIC_ROOT = os.path.join(BASE_DIR, 'collect_static').replace('\\', '/')
150
+
151
+STATIC_URL = '/static/'
152
+
153
+STATICFILES_FINDERS = (
154
+    'django.contrib.staticfiles.finders.FileSystemFinder',
155
+    'django.contrib.staticfiles.finders.AppDirectoriesFinder',
156
+    # 'django.contrib.staticfiles.finders.DefaultStorageFinder',
157
+)
158
+
159
+MEDIA_ROOT = os.path.join(BASE_DIR, 'media').replace('\\', '/')
160
+
161
+MEDIA_URL = '/media/'
162
+
163
+# Redis 设置
164
+REDIS = {
165
+    'default': {
166
+        'HOST': '127.0.0.1',
167
+        'PORT': 6379,
168
+        'USER': '',
169
+        'PASSWORD': '',
170
+        'db': 0,
171
+    }
172
+}
173
+
174
+# 微信设置
175
+WECHAT = {
176
+    'JSAPI': {
177
+        'token': '5201314',
178
+        'appID': '',
179
+        'appsecret': '',
180
+        'mchID': '',
181
+        'apiKey': '',
182
+        'mch_cert': '',
183
+        'mch_key': '',
184
+        'redpacket': {
185
+
186
+        }
187
+    },
188
+}
189
+
190
+# 微信授权设置
191
+WECHAT_BASE_REDIRECT_URI = 'https://api.pai.ai/base_redirect'
192
+WECHAT_USERINFO_REDIRECT_URI = 'https://api.pai.ai/userinfo_redirect'
193
+WECHAT_OAUTH2_RETRY_REDIRECT_URI = 'https://api.pai.ai/wx_oauth2?redirect_url={}'
194
+
195
+WECHAT_OAUTH2_REDIRECT_URL = 'https://api.pai.ai/wx_oauth2?redirect_url={}'
196
+
197
+# LOGIT 设置
198
+LOGIT_BODY_FLAG = True
199
+LOGIT_RES_FLAG = True
200
+
201
+DOMAIN = ''
202
+
203
+try:
204
+    from local_settings import *
205
+except ImportError:
206
+    pass
207
+
208
+try:
209
+    from func_settings import redis_connect
210
+    REDIS_CACHE = redis_connect(REDIS.get('default', {}))
211
+
212
+    DJLOGIT = {
213
+        'level': 'DEBUG',
214
+        'class': 'rlog.RedisListHandler',
215
+        'redis_client': REDIS_CACHE,
216
+        'key': 'django:logit:tamron',
217
+        'formatter': 'verbose',
218
+    }
219
+except ImportError:
220
+    REDIS_CACHE = None
221
+
222
+# 日志设置
223
+LOGGING = {
224
+    'version': 1,
225
+    'disable_existing_loggers': False,
226
+    'formatters': {
227
+        'verbose': {
228
+            'format': '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s'
229
+        },
230
+        'simple': {
231
+            'format': '%(levelname)s %(message)s'
232
+        },
233
+    },
234
+    'handlers': {
235
+        'logit': DJLOGIT,
236
+        'console': {
237
+            'level': 'DEBUG',
238
+            'class': 'logging.StreamHandler',
239
+            'formatter': 'verbose'
240
+        },
241
+    },
242
+    'loggers': {
243
+        'logit': {
244
+            'handlers': ['logit'],
245
+            'level': 'DEBUG',
246
+            'propagate': True,
247
+        },
248
+        'console': {
249
+            'handlers': ['console'],
250
+            'level': 'DEBUG',
251
+            'propagate': True,
252
+        },
253
+    },
254
+}

BIN
tamron/settings.pyc


+ 300 - 0
tamron/static/tamron/js/jswe.js

@@ -0,0 +1,300 @@
1
+!(function(e, t) {
2
+    var config = {
3
+        wxconfig: 'http://api.pai.ai/wx/jsapi_signature',
4
+        callback: 'callback'
5
+    }, wxData = {
6
+        debug: false,
7
+        imgUrl: '',
8
+        link: '',
9
+        desc: '',
10
+        title: '',
11
+        timeLine: ''
12
+    }, wxConfig = {
13
+        hide: false,
14
+        close: false
15
+    }, jsApiList = [
16
+        'checkJsApi',
17
+        'onMenuShareTimeline',
18
+        'onMenuShareAppMessage',
19
+        'onMenuShareQQ',
20
+        'onMenuShareWeibo',
21
+        'hideMenuItems',
22
+        'showMenuItems',
23
+        'hideAllNonBaseMenuItem',
24
+        'showAllNonBaseMenuItem',
25
+        'translateVoice',
26
+        'startRecord',
27
+        'stopRecord',
28
+        'onRecordEnd',
29
+        'playVoice',
30
+        'pauseVoice',
31
+        'stopVoice',
32
+        'uploadVoice',
33
+        'downloadVoice',
34
+        'chooseImage',
35
+        'previewImage',
36
+        'uploadImage',
37
+        'downloadImage',
38
+        'getNetworkType',
39
+        'openLocation',
40
+        'getLocation',
41
+        'hideOptionMenu',
42
+        'showOptionMenu',
43
+        'closeWindow',
44
+        'scanQRCode',
45
+        'chooseWXPay',
46
+        'openEnterpriseRedPacket',
47
+        'openProductSpecificView',
48
+        'addCard',
49
+        'chooseCard',
50
+        'openCard'
51
+    ], wxApiFun
52
+
53
+    function isOpenOnPC() {  // 判断当前网页是否在 PC 浏览器中打开
54
+        var ua = navigator.userAgent
55
+        return /windows nt/i.test(ua) || /macintosh/i.test(ua) || /linux x86_64/i.test(ua)
56
+    }
57
+
58
+    function isOpenInWeixin() {  // 判断当前网页是否在微信内置浏览器中打开
59
+        return /micromessenger/i.test(navigator.userAgent)
60
+    }
61
+
62
+    function getWeixinVersion() {
63
+        var ua = navigator.userAgent,
64
+            mt = ua.match(/micromessenger\/([\d.]+)/i)
65
+        return (mt ? mt[1] : '')
66
+    }
67
+
68
+    // This function checks whether Wechat is the appointed version or not
69
+    // Cmp: http://jsperf.com/regexp-test-vs-indexof-ignore-upper-and-lower
70
+    function isWeixinVersion(version) {
71
+        // return new RegExp('micromessenger/' + version , 'i').test(navigator.userAgent)
72
+        return navigator.userAgent.toLowerCase().indexOf('micromessenger/' + version) != -1
73
+    }
74
+
75
+    function hideOptionMenu() {
76
+        wxConfig.hide = true
77
+        fixedWxData()
78
+    }
79
+
80
+    function showOptionMenu() {
81
+        wxConfig.hide = false
82
+        fixedWxData()
83
+    }
84
+
85
+    function closeWindow() {
86
+        wxConfig.close = true
87
+        fixedWxData()
88
+    }
89
+
90
+    function wxReady(data) {
91
+        data = typeof data === 'object' ? data : JSON.parse(data)
92
+        wx.config({
93
+            debug: wxData.debug,
94
+            appId: data.appId,
95
+            timestamp: data.timestamp,
96
+            nonceStr: data.nonceStr,
97
+            signature: data.signature,
98
+            jsApiList: jsApiList
99
+        })
100
+
101
+        var callbacks = {
102
+            trigger: function (res) {
103
+                // alert('用户点击发送给朋友')
104
+                if (JSWE.wxTrigger) {JSWE.wxTrigger(res)}
105
+            },
106
+            success: function (res) {
107
+                // alert('已分享')
108
+                if (JSWE.wxSuccess) {JSWE.wxSuccess(res)}
109
+            },
110
+            cancel: function (res) {
111
+                // alert('已取消')
112
+                if (JSWE.wxCancel) {JSWE.wxCancel(res)}
113
+            },
114
+            fail: function (res) {
115
+                // alert(JSON.stringify(res))
116
+                if (JSWE.wxFail) {JSWE.wxFail(res)}
117
+            }
118
+        }, shareInfo = function(flag) {
119
+            var _share = {
120
+                title: flag ? wxData.title : (wxData.timeLine || wxData.desc),
121
+                link: wxData.link,
122
+                imgUrl: wxData.imgUrl,
123
+                trigger: callbacks.trigger,
124
+                success: callbacks.success,
125
+                cancel: callbacks.cancel,
126
+                fail: callbacks.fail
127
+            }
128
+            if (flag) _share.desc = wxData.desc
129
+            return _share
130
+        }, wxShareApi = function() {
131
+            // 2. 分享接口
132
+            // 2.1 监听“分享给朋友”,按钮点击、自定义分享内容及分享结果接口
133
+            wx.onMenuShareAppMessage(shareInfo(1))
134
+            // 2.2 监听“分享到朋友圈”按钮点击、自定义分享内容及分享结果接口
135
+            wx.onMenuShareTimeline(shareInfo(0))
136
+            // 2.3 监听“分享到QQ”按钮点击、自定义分享内容及分享结果接口
137
+            wx.onMenuShareQQ(shareInfo(1))
138
+            // 2.4 监听“分享到微博”按钮点击、自定义分享内容及分享结果接口
139
+            wx.onMenuShareWeibo(shareInfo(1))
140
+        }, wxMenuApi = function () {
141
+            // 8. 界面操作接口
142
+            // 8.1 隐藏右上角菜单
143
+            // 8.2 显示右上角菜单
144
+            if (wxConfig.hide) {wx.hideOptionMenu()} else {wx.showOptionMenu()}
145
+            // 8.7 关闭当前窗口
146
+            if (wxConfig.close) {wx.closeWindow()}
147
+        }, wxApi = function () {
148
+            wxShareApi()
149
+            wxMenuApi()
150
+        }
151
+
152
+        wx.ready(wxApi)
153
+
154
+        return wxApiFun = wxApi
155
+    }
156
+
157
+    if (isOpenInWeixin() || isOpenOnPC()) {
158
+        if ('undefined' !== typeof JSWE_CONF_UPDATE) JSWE_CONF_UPDATE(config)
159
+        $.ajax({
160
+            url: config.wxconfig,
161
+            type: 'get',
162
+            dataType: 'jsonp',
163
+            jsonpCallback: config.callback,
164
+            data: {
165
+                url: window.location.href.split('#')[0]
166
+            },
167
+            success: wxReady
168
+        })
169
+    }
170
+
171
+    function initWxData(data, flag) {
172
+        for(var d in data) {if (d in wxData) wxData[d] = data[d]}
173
+        if (flag) fixedWxData()
174
+    }
175
+
176
+    function changeWxData(key, value, flag) {
177
+        if (key in falDwxDataata) {wxData[key] = value}
178
+        if (flag) fixedWxData()
179
+    }
180
+
181
+    function fixedWxData() {
182
+        if ('undefined' !== typeof wxApiFun) wxApiFun()
183
+    }
184
+
185
+    // 5 图片接口
186
+    // 5.1 拍照、本地选图
187
+    var images = {
188
+        localIds: [],
189
+        serverIds: []
190
+    };
191
+    function chooseImage(count, directUpload, isShowProgressTips) {
192
+        if ('undefined' === typeof count) {count = 9}
193
+        if ('undefined' === typeof directUpload) {directUpload = false}
194
+        if ('undefined' === typeof isShowProgressTips) {isShowProgressTips = 1}
195
+        wx.chooseImage({
196
+            count: count, // 默认9
197
+            sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
198
+            sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
199
+            success: function (res) {
200
+                var localIds = res.localIds; // 返回选定照片的本地ID列表,localId可以作为img标签的src属性显示图片
201
+                images.localIds = localIds;
202
+                // 判断是否直接上传
203
+                if (directUpload) {setTimeout(uploadImages(localIds, isShowProgressTips), 100)}
204
+                // 拍照、本地选图成功后的回调函数
205
+                if (JSWE.wxChooseImageSuccess) {JSWE.wxChooseImageSuccess(res)}
206
+            }
207
+        });
208
+    }
209
+
210
+    // 5.3 上传图片
211
+    function uploadImage(localId, isShowProgressTips) {
212
+        // 上传图片为异步处理,重复上传同一图片,返回的serverId也是不同的
213
+        wx.uploadImage({
214
+            localId: localId, // 需要上传的图片的本地ID,由chooseImage接口获得
215
+            isShowProgressTips: 1, // 默认为1,显示进度提示
216
+            success: function (res) {
217
+                var serverId = res.serverId; // 返回图片的服务器端ID
218
+                images.serverIds.push(serverId);
219
+                // 上传图片成功后的回调函数
220
+                if (JSWE.wxUploadImageSuccess) {JSWE.wxUploadImageSuccess(res)}
221
+            }
222
+        });
223
+    }
224
+
225
+    function uploadImages(localIds, isShowProgressTips) {
226
+        if ('undefined' === typeof localIds) {localIds = images.localIds}
227
+        if ('undefined' === typeof isShowProgressTips) {isShowProgressTips = 1}
228
+        images.serverIds = [];
229
+        for (var index in localIds) {uploadImage(localIds[index], isShowProgressTips)}
230
+    }
231
+
232
+    // 10 微信支付接口
233
+    // 10.1 发起一个支付请求
234
+    function chooseWXPay(wxpay_params) {
235
+        wx.chooseWXPay({
236
+            timestamp: wxpay_params.timeStamp, // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
237
+            nonceStr: wxpay_params.nonceStr, // 支付签名随机串,不长于 32 位
238
+            package: wxpay_params.package, // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=***)
239
+            signType: wxpay_params.signType, // 签名方式,默认为'SHA1',使用新版支付需传入'MD5'
240
+            paySign: wxpay_params.paySign, // 支付签名
241
+            success: function (res) {
242
+                // 支付成功后的回调函数
243
+                if (JSWE.wxPaySuccess) {JSWE.wxPaySuccess(res)}
244
+            }
245
+        })
246
+    }
247
+
248
+    // xx 微信原生企业红包接口
249
+    // xx.1 发起一个发送原生企业红包请求
250
+    function openEnterpriseRedPacket(wxredpack_params) {
251
+        wx.openEnterpriseRedPacket({
252
+            timeStamp: wxredpack_params.timeStamp, // 红包签名时间戳,注意原生企业红包接口timeStamp字段名需大写其中的S字符,而支付接口timeStamp字段名无需大写其中的S字符。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
253
+            nonceStr: wxredpack_params.nonceStr, // 红包签名随机串,不长于 32 位
254
+            package: encodeURIComponent(wxredpack_params.package), // 发放红包接口返回的prepay_id参数值,提交格式如:prepay_id=***)
255
+            signType: wxredpack_params.signType, // 签名方式,默认为'SHA1',使用新版支付需传入'MD5'
256
+            paySign: wxredpack_params.paySign, // 红包签名
257
+            success: function (res) {
258
+                // 发送原生企业红包成功后的回调函数
259
+                if (JSWE.wxEnterpriseRedPacketSuccess) {JSWE.wxEnterpriseRedPacketSuccess(res)}
260
+            }
261
+        })
262
+    }
263
+
264
+    var v = {
265
+        version: '1.0.5',
266
+
267
+        // Basic Vars
268
+        config: config,
269
+        wxData: wxData,
270
+        jsApiList: jsApiList,
271
+
272
+        // Weixin Function
273
+        isOpenInWeixin: isOpenInWeixin,
274
+        getWeixinVersion: getWeixinVersion,
275
+        isWeixinVersion: isWeixinVersion,
276
+
277
+        // Menu Function
278
+        hideOptionMenu: hideOptionMenu,
279
+        showOptionMenu: showOptionMenu,
280
+        closeWindow: closeWindow,
281
+
282
+        // Share Function
283
+        initWxData: initWxData,
284
+        changeWxData: changeWxData,
285
+        fixedWxData: fixedWxData,
286
+
287
+        // Image Function
288
+        images: images,
289
+        chooseImage: chooseImage,
290
+        uploadImage: uploadImage,
291
+        uploadImages: uploadImages,
292
+
293
+        // Pay Function
294
+        chooseWXPay: chooseWXPay,
295
+
296
+        // EnterpriseRedPacket Function
297
+        openEnterpriseRedPacket: openEnterpriseRedPacket
298
+    }
299
+    e.JSWE = e.V = v
300
+})(window)

+ 33 - 0
tamron/urls.py

@@ -0,0 +1,33 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+"""tamron URL Configuration
4
+
5
+The `urlpatterns` list routes URLs to views. For more information please see:
6
+    https://docs.djangoproject.com/en/1.8/topics/http/urls/
7
+Examples:
8
+Function views
9
+    1. Add an import:  from my_app import views
10
+    2. Add a URL to urlpatterns:  url(r'^$', views.home, name='home')
11
+Class-based views
12
+    1. Add an import:  from other_app.views import Home
13
+    2. Add a URL to urlpatterns:  url(r'^$', Home.as_view(), name='home')
14
+Including another URLconf
15
+    1. Add an import:  from blog import urls as blog_urls
16
+    2. Add a URL to urlpatterns:  url(r'^blog/', include(blog_urls))
17
+"""
18
+from django.conf.urls import include, url
19
+from django.contrib import admin
20
+
21
+from page import info_views, oauth_views, sale_views
22
+
23
+
24
+urlpatterns = [
25
+    url(r'^admin/', include(admin.site.urls)),
26
+    url(r'^api/', include('api.urls', namespace='api')),
27
+]
28
+
29
+urlpatterns += [
30
+    url(r'^page/clerk$', oauth_views.clerk_oauth, name='clerk_oauth'),  # 店员授权页面
31
+    url(r'^page/clerk/sale$', sale_views.clerk_sale_oauth, name='clerk_sale_oauth'),  # 店员销售授权页面
32
+    url(r'^page/clerk/info$', info_views.clerk_info_oauth, name='clerk_info_oauth'),  # 店员信息授权页面
33
+]

BIN
tamron/urls.pyc


+ 2 - 0
tamron/uwsgi.bak/shutdown.sh

@@ -0,0 +1,2 @@
1
+killall -9 uwsgi
2
+echo "2敏加油~~~!!!↖(^ω^)↗"

+ 2 - 0
tamron/uwsgi.bak/startup.sh

@@ -0,0 +1,2 @@
1
+nohup uwsgi --ini pai2.ini &>pai2.log &
2
+echo "Start Success !!!"

+ 27 - 0
tamron/uwsgi.bak/tamron.ini

@@ -0,0 +1,27 @@
1
+# tamron_uwsgi.ini file
2
+[uwsgi]
3
+
4
+# Django-related settings
5
+# the base directory (full path)
6
+chdir           = /home/paiai/work/tamron
7
+# Django's wsgi file
8
+module          = tamron.wsgi
9
+# the virtualenv (full path)
10
+# home            = /path/to/virtualenv
11
+
12
+# process-related settings
13
+# master
14
+master          = true
15
+# maximum number of worker processes
16
+processes       = 10
17
+# the socket (use the full path to be safe
18
+socket          = /home/paiai/work/tamron/tamron/uwsgi/tamron.sock
19
+# ... with appropriate permissions - may be needed
20
+chmod-socket    = 777
21
+# clear environment on exit
22
+vacuum          = true
23
+
24
+# 11: Resource temporarily unavailable
25
+reload-mercy    = 64
26
+max-requests    = 8192
27
+listen          = 4096

+ 35 - 0
tamron/uwsgi.bak/tamron_nginx.conf

@@ -0,0 +1,35 @@
1
+# tamron_nginx.conf
2
+
3
+# the upstream component nginx needs to connect to
4
+upstream pai2 {
5
+    # server unix:///home/paiai/work/tamron/tamron/uwsgi/tamron.sock; # for a file socket
6
+    server 127.0.0.1:8888; # for a web port socket (we'll use this first)
7
+}
8
+
9
+# configuration of the server
10
+server {
11
+    # the port your site will be served on
12
+    listen      80;
13
+    # the domain name it will serve for
14
+    server_name .tamron.xfoto.com.cn; # substitute your machine's IP address or FQDN
15
+    charset     utf-8;
16
+
17
+    # max upload size
18
+    client_max_body_size 75M;   # adjust to taste
19
+
20
+    # Django media
21
+    location /media  {
22
+        alias /home/paiai/work/tamron/media;  # your Django project's media files - amend as required
23
+    }
24
+
25
+    location /static {
26
+        alias /home/paiai/work/tamron/collect_static; # your Django project's static files - amend as required
27
+    }
28
+
29
+    # Finally, send all non-media requests to the Django server.
30
+    location / {
31
+        # uwsgi_pass  tamron;
32
+        proxy_pass  http://tamron;
33
+        include     /home/paiai/work/tamron/tamron/uwsgi/uwsgi_params; # the uwsgi_params file you installed
34
+    }
35
+}

+ 15 - 0
tamron/uwsgi.bak/uwsgi_params

@@ -0,0 +1,15 @@
1
+uwsgi_param	QUERY_STRING		$query_string;
2
+uwsgi_param	REQUEST_METHOD		$request_method;
3
+uwsgi_param	CONTENT_TYPE		$content_type;
4
+uwsgi_param	CONTENT_LENGTH		$content_length;
5
+
6
+uwsgi_param	REQUEST_URI		$request_uri;
7
+uwsgi_param	PATH_INFO		$document_uri;
8
+uwsgi_param	DOCUMENT_ROOT		$document_root;
9
+uwsgi_param	SERVER_PROTOCOL		$server_protocol;
10
+uwsgi_param	UWSGI_SCHEME		$scheme;
11
+
12
+uwsgi_param	REMOTE_ADDR		$remote_addr;
13
+uwsgi_param	REMOTE_PORT		$remote_port;
14
+uwsgi_param	SERVER_PORT		$server_port;
15
+uwsgi_param	SERVER_NAME		$server_name;

+ 17 - 0
tamron/wsgi.py

@@ -0,0 +1,17 @@
1
+"""
2
+WSGI config for tamron project.
3
+
4
+It exposes the WSGI callable as a module-level variable named ``application``.
5
+
6
+For more information on this file, see
7
+https://docs.djangoproject.com/en/1.8/howto/deployment/wsgi/
8
+"""
9
+
10
+import os
11
+
12
+from django.core.wsgi import get_wsgi_application
13
+
14
+
15
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "tamron.settings")
16
+
17
+application = get_wsgi_application()

BIN
tamron/wsgi.pyc


+ 0 - 0
utils/__init__.py


BIN
utils/__init__.pyc


+ 0 - 0
utils/error/__init__.py


BIN
utils/error/__init__.pyc


+ 62 - 0
utils/error/errno_utils.py

@@ -0,0 +1,62 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+from StatusCode import BaseStatusCode, StatusCodeField
4
+
5
+
6
+class FranchiserStatusCode(BaseStatusCode):
7
+    """ 店员相关错误码 4001xx """
8
+    CHISER_NOT_FOUND = StatusCodeField(400001, 'Chiser Not Found', description=u'经销商不存在')
9
+
10
+
11
+class SaleclerkStatusCode(BaseStatusCode):
12
+    """ 店员相关错误码 4001xx """
13
+    CLERK_NOT_FOUND = StatusCodeField(400101, 'Clerk Not Found', description=u'店员不存在')
14
+    # 手机号
15
+    CLERK_PHONE_ALREADY_EXISTS = StatusCodeField(400105, 'Clerk Phone Already Exists', description=u'手机号已经存在')
16
+    # 状态
17
+    CLERK_ALREADY_NOT_UNVERIFIED = StatusCodeField(400110, 'Clerk Already Not Unverified', description=u'店员帐号已激活')
18
+    CLERK_NOT_ACTIVATED = StatusCodeField(400115, 'Clerk Not Activated', description=u'店员帐号未激活')
19
+
20
+
21
+class ProductModelStatusCode(BaseStatusCode):
22
+    """ 型号相关错误码 4010xx """
23
+    MODEL_NOT_FOUND = StatusCodeField(401001, 'Model Not Found', description=u'型号不存在')
24
+
25
+
26
+class ProductStatusCode(BaseStatusCode):
27
+    """ 产品相关错误码 4020xx """
28
+    PRODUCT_NOT_FOUND = StatusCodeField(402001, 'Product Not Found', description=u'产品不存在')
29
+    # 状态
30
+    PRODUCT_HAS_USED = StatusCodeField(402011, 'Product Has Used', description=u'产品已使用')
31
+
32
+
33
+class OrderStatusCode(BaseStatusCode):
34
+    """ 订单/支付相关错误码 4040xx """
35
+    WX_UNIFIED_ORDER_FAIL = StatusCodeField(404000, 'WX Unified Order Fail', description=u'微信统一下单失败')
36
+    WX_ORDER_NOT_FOUND = StatusCodeField(404001, 'WX Order Not Found', description=u'订单不存在')
37
+    WX_ORDER_NOT_PAY = StatusCodeField(404002, 'WX Order Not Pay', description=u'订单未支付')
38
+    WX_ORDER_PAYING = StatusCodeField(404003, 'WX Order Paying', description=u'订单支付中')
39
+    WX_ORDER_PAY_FAIL = StatusCodeField(404009, 'WX Order Pay Fail', description=u'微信支付失败')
40
+    SIGN_CHECK_FAIL = StatusCodeField(404010, 'Sign Check Fail', description=u'签名校验失败')
41
+    FEE_CHECK_FAIL = StatusCodeField(404011, 'FEE Check Fail', description=u'金额校验失败')
42
+    NO_DETAIL_PERMISSION = StatusCodeField(404015, 'No Detail Permission', description=u'无详情权限')
43
+    WX_ORDER_PAID_ALREADY_EXISTS = StatusCodeField(404020, 'WX Order Paid Already Exists', description=u'照片已购买')
44
+
45
+
46
+class PayStatusCode(BaseStatusCode):
47
+    """ 支付相关错误码 4041xx """
48
+
49
+
50
+class WithdrawStatusCode(BaseStatusCode):
51
+    """ 提现相关错误码 4042xx """
52
+    BALANCE_NOT_ENOUGH = StatusCodeField(404200, 'Balance Not Enough', description=u'提现金额不足')
53
+
54
+
55
+class MessageStatusCode(BaseStatusCode):
56
+    """ 消息相关错误码 4090xx """
57
+    MESSAGE_NOT_FOUND = StatusCodeField(409001, 'Message Not Found', description=u'消息不存在')
58
+
59
+
60
+class TokenStatusCode(BaseStatusCode):
61
+    """ 票据相关错误码 4090xx """
62
+    TOKEN_NOT_FOUND = StatusCodeField(409901, 'Token Not Found', description=u'票据不存在')

BIN
utils/error/errno_utils.pyc


+ 18 - 0
utils/error/response_utils.py

@@ -0,0 +1,18 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+from django.http import JsonResponse
4
+from StatusCode import StatusCodeField
5
+
6
+
7
+def response_data(status_code=200, message=None, description=None, data={}, **kwargs):
8
+    return dict({
9
+        'status': status_code,
10
+        'message': message,
11
+        'description': description,
12
+        'data': data,
13
+    }, **kwargs)
14
+
15
+
16
+def response(status_code=200, message=None, description=None, data={}, **kwargs):
17
+    message, description = (message or status_code.message, description or status_code.description) if isinstance(status_code, StatusCodeField) else (message, description)
18
+    return JsonResponse(response_data(status_code, message, description, data, **kwargs), safe=False)

BIN
utils/error/response_utils.pyc


+ 0 - 0
utils/redis/__init__.py


BIN
utils/redis/__init__.pyc


+ 6 - 0
utils/redis/connect.py

@@ -0,0 +1,6 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+from django.conf import settings
4
+
5
+
6
+r = settings.REDIS_CACHE

BIN
utils/redis/connect.pyc


+ 68 - 0
utils/redis/rkeys.py

@@ -0,0 +1,68 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+# 唯一标识相关
4
+UUID_LIST = 'uuid:list'  # List,唯一标识列表
5
+
6
+# 用户相关
7
+PROFILE_INFO = 'profile:info:%s'  # STRING,用户信息,user_id
8
+
9
+# 导游相关
10
+TOUR_GUIDE_GROUP_GEO_INFO = 'tour:guide:group:geo:info:%s'  # ZSET,旅游团地理位置信息,group_id
11
+TOUR_GUIDE_GROUP_GEO_SUBMIT_DT = 'tour:guide:group:geo:submit:dt:%s'  # ZSET,旅游团地理位置最后上传时间,group_id
12
+TOUR_GUIDE_GROUP_CUR_SESSION = 'tour:guide:group:cur:session:%s'  # STRING,旅游团当前Session,group_id,导游设置集合时间的时候更新
13
+TOUR_GUIDE_GROUP_CUR_GATHER_INFO = 'tour:guide:group:cur:gather:info:%s'  # STRING,旅游团当前Session,group_id,导游设置集合时间的时候更新
14
+TOUR_GUIDE_GROUP_USER_GEO_LIST = 'tour:guide:group:user:geo:list:%s:%s:%s'  # LIST,旅游团当前用户地理位置列表,group_id、session_id、user_id
15
+
16
+TOUR_GUIDE_GROUP_USER_OWN = 'tour:guide:group:user:own:%s'  # STRING,导游当前拥有的旅行团,user_id,导游创建旅行团的时候更新
17
+TOUR_GUIDE_GROUP_USER_BELONG = 'tour:guide:group:user:belong:%s'  # STRING,用户当前所属旅行团,user_id,用户加入旅行团的时候更新
18
+
19
+# 群组相关
20
+GROUP_INFO = 'group:info:%s'  # STRING,群组信息,group_id
21
+
22
+# 群组用户相关
23
+GROUP_USERS_INFO = 'group:users:info:%s'  # STRING,群组用户信息,group_id
24
+GROUP_USERS_KV_INFO = 'group:users:kv:info:%s'  # STRING,群组用户信息,group_id
25
+GROUP_USERS_APPLYING_SET = 'group:users:applying:set:%s'  # SET,群组用户申请集合,group_id
26
+GROUP_USERS_PASSED_SET = 'group:users:passed:set:%s'  # SET,群组用户通过集合,group_id
27
+GROUP_USERS_REFUSED_SET = 'group:users:refused:set:%s'  # SET,群组用户拒绝集合,group_id
28
+GROUP_USERS_DELETED_SET = 'group:users:deleted:set:%s'  # SET,群组用户移除集合,group_id
29
+GROUP_USERS_QUIT_SET = 'group:users:quit:set:%s'  # SET,群组用户退出集合,group_id
30
+
31
+# 群组照片相关
32
+GROUP_PHOTO_DATA = 'group:photo:data:%s'  # STRING,群组数据记录,group_id
33
+GROUP_PHOTO_THUMB_UP = 'group:photo:thumb:up:%s:%s'  # STRING,群组照片用户点赞记录,photo_id、user_id
34
+GROUP_PHOTO_COMMENT_LIST = 'group:photo:comment:list:%s'  # STRING,群组照片用户评论列表,photo_id
35
+GROUP_PHOTO_THUMB_UP_LIST = 'group:photo:thumb:up:list:%s'  # STRING,群组照片用户点赞列表,photo_id
36
+GROUP_PHOTO_WATCHER_SET = 'group:photo:watcher:set:%s'  # SET,群组照片用户关注集合,photo_id,关注即评论点赞
37
+GROUP_LAST_PHOTO_PK = 'group:last:photo:pk:%s'  # STRING,群组最后一张照片PK,group_id
38
+
39
+# 摄影师照片相关
40
+LENSMAN_PHOTO_ORDER_RECORD = 'lensman:photo:order:record:%s:%s'  # STRING,摄影师照片购买记录,photo_id、user_id
41
+
42
+# 摄影师简报相关
43
+# 收入
44
+TOTAL_INCOME = 'total:income:%s:%s'  # STRING,总收入,user_id、photo_type
45
+WEEK_INCOME = 'week:income:%s:%s:%s'  # STRING,周收入,user_id、photo_type、Week.thisweek().isoformat()
46
+TODAY_INCOME = 'today:income:%s:%s:%s'  # STRING,日收入,user_id、photo_type、tc.local_string(format='%Y%m%d')
47
+# 上传
48
+TODAY_UPLOAD_PHOTO_AMOUNT = 'today:upload:photo:amount:%s:%s'  # STRING,日上传照片数量,user_id、tc.local_string(format='%Y%m%d')
49
+# 售出
50
+WEEK_SOLD = 'week:sold:%s:%s:%s'  # STRING,周售出,user_id、photo_type、Week.thisweek().isoformat()
51
+
52
+# 摄影师定价相关
53
+LENSMAN_PHOTO_PRICE_FIXED = 'lensman:photo:price:fixed:%s'  # STRING,摄影师照片定价(单位:分),user_id
54
+
55
+# 系统消息相关
56
+SYSTEM_MESSAGE_READ_INFO = 'system:message:read:info:%s'  # STRING,系统消息读取信息,user_id
57
+SYSTEM_MESSAGE_DELETED_INFO = 'system:message:deleted:info:%s'  # STRING,系统消息删除信息,user_id
58
+
59
+# 游客入口相关
60
+GUEST_ENTRANCE_CONTROL_INFO = 'guest:entrance:control:info:%s'  # STRING,游客入口控制信息,src
61
+
62
+# APP 相关
63
+LATEST_APP_INFO = 'latest:app:info:%s'  # STRING,最新 APP 信息,src
64
+APP_SETTINGS_INFO = 'app:settings:info:%s:%s:%s'  # STRING,APP 设置信息,platform、channel、version
65
+APP_PATCH_INFO = 'app:patch:info:%s:%s:%s'  # STRING,APP 补丁信息,platform、version、src
66
+
67
+# BOX 相关
68
+BOX_PROGRAM_VERSION_INFO = 'box:program:version:info'  # STRING,BOX 程序版本信息